【问题标题】:PHP - Service layer class instantiation causing infinite loopPHP - 服务层类实例化导致无限循环
【发布时间】:2017-01-07 12:46:26
【问题描述】:

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

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

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
     ...
   }

我使用的是 Slim 3,我使用它的 Container 类来实例化和注入所有依赖项。

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

我正在尝试在 Java/Spring 中实现类似的功能,您的类中有不同的服务,它们使用 Spring 连接到其中,因此您不必担心循环依赖。

除了基础之外,我对 PHP 不太熟悉。

如果需要更多信息,请告诉我。

【问题讨论】:

    标签: php oop design-patterns slim


    【解决方案1】:

    Pimple 在 Slim3 中用作依赖容器,不如 Java f.ex 中的 Spring 强大。它只是一个简单的容器,只有基本的功能。

    所以当只使用 pimple 函数时,您需要自己初始化具有循环依赖关系的对象:

    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'];
    

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

    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]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-21
      • 1970-01-01
      • 2011-03-24
      • 2018-04-15
      • 2014-04-22
      相关资源
      最近更新 更多