PHP - 服务层类实例化导致无限循环

时间:2017-01-07 12:46:26

标签: php oop design-patterns slim

我有服务层类来执行业务逻辑。

我有一个班级UserService,它执行与用户角色相关的服务,例如检查用户是否为管理员,用户是否有权访问项目,用户是否具有特定角色等。还有另一个班级说{{ 1}}处理项目相关的事情,如获取项目成员,项目详细信息等。

ProjectService

我正在使用Slim 3,我使用它的UserService $projectService; //class variable hasProjectAccess(){ { ... projectMember = projectService->getProjectMembers(); ... } isUserAdmin(){ return true|false; //just an example } ProjectService $userService; //class variable getProjectMembers(){ { ... perform some logic to create array of members ... if(userService.isUserAdmin()) .. perform some other logic ... } 类来实例化并注入所有依赖项。

现在,当我尝试实例化Container类时,我必须在其中实例化UserService类(使用setters方法),而后者必须实例化UserService类....等等。 ..创建一个无限循环(循环依赖)。

我正在尝试实现像Java / Spring这样的东西,你在类中需要不同的服务,并且使用Spring连接到它,所以你不必担心循环依赖。

除了基础知识,我对PHP并不熟悉。

如果需要更多信息,请与我们联系。

1 个答案:

答案 0 :(得分:0)

在Slim3中用作依赖容器的

Pimple并不像Java中的Spring那样强大。它只是一个简单的容器,只具有基本功能。

因此,当只使用疙瘩函数时,您需要自己初始化具有循环依赖性的对象:

class A {
    private $b;
    public function __construct(B $b) { $this->b = $b; }
}
class B {
    private $a;
    public function setA(A $a) { $this->a = $a; }
}

$container = new \Slim\Container;
$b = new B;
$a = new A($b);
$b->setA($a);

$container['A'] = function($c) use ($a) {
    return $a;
};
$container['B'] = function($c) use ($b) {
    return $b;
};
$aFromContainer = $container['A'];

我对苗条容器进行了一些小改动,可以自动化这个过程(通过这项工作,我不知道它在大型项目中的表现如何)

class MyContainer extends \Slim\Container 
        implements \Interop\Container\ContainerInterface {
    private $resolveStack = [];
    private $resolveLater = [];

    /**
     * @see \Pimple\Container::offsetSet()
     *
     * Additionally define objects which will be later set with a method.
     */
    public function resolveLater(string $id, callable $value, array $later) {
        $this[$id] = $value;
        foreach($later as $item) {
            if(!isset($this->resolveLater[$item])) $this->resolveLater[$item] = [];
            $this->resolveLater[$item][] = $id;
        }
    }

    /**
     * @see \Pimple\Container::offsetGet()
     *
     * Additionally set objects which were previously defined in #resolveLater.
     */
    public function offsetGet($id) {
        if(isset($this->resolveStack[$id])) { return $this->resolveStack[$id]; }
        $this->resolveStack[$id] = parent::offsetGet($id);
        if(isset($this->resolveLater[$id])) {
            foreach($this->resolveLater[$id] as $item) {
                $this[$item]->{'set' . $id}($this->resolveStack[$id]);
            }
        }
        return array_pop($this->resolveStack);
    }
}

上述示例:

class A {
    public function setB(B $b) { $this->b = $b; }
    public function setC(C $c) { $this->c = $c; }
}
class B {
    public function setA(A $a) { $this->a = $a; }
    public function setC(C $c) { $this->c = $c; }
}
class C {
    public function setA(A $a) { $this->a = $a; }
    public function setB(B $b) { $this->b = $b; }
}
$container = new MyContainer;
$container->resolveLater('A', function($container) {
    return new A;
}, ['B', 'C']);
$container->resolveLater('B', function($container) {
    return new B;
}, ['A', 'C']);
$container->resolveLater('C', function($container) {
    return new C;
}, ['A','B']);
$a = $container['C'];
var_dump($a);

这将输出如下内容:

object(C)[20]
  public 'b' =>
    object(B)[22]
      public 'a' =>
        object(A)[21]
          public 'b' =>
            &object(B)[22]
          public 'c' =>
            &object(C)[20]
      public 'c' =>
        &object(C)[20]
  public 'a' =>
    object(A)[21]
      public 'b' =>
        object(B)[22]
          public 'a' =>
            &object(A)[21]
          public 'c' =>
            &object(C)[20]
      public 'c' =>
        &object(C)[20]