【问题标题】:PHP pimple cross dependencyPHP疙瘩交叉依赖
【发布时间】:2013-07-18 09:14:27
【问题描述】:

我有两个相互依赖的类:

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

我需要像这样将它们包裹在 Pimple 中:

$c = new \Pimple();
$c['aService'] = function($c){
    return new A($c['bService']);
}
$c['bService'] = function($c){
    return new B($c['aService']);
}

但不幸的是我骑自行车:

Fatal error: Maximum function nesting level of '100' reached, aborting!

有没有办法在不循环的情况下达到这种交叉依赖?或者我只能使用单向依赖?

【问题讨论】:

    标签: php dependency-injection dependencies service-locator pimple


    【解决方案1】:

    这让我想起了baboushka的

    当然,你肯定会在这里得到无限递归。两个函数相互调用,每次返回一个新实例,将调用的返回值传递给它们的函数计数器部分,然后再次调用该函数,该函数再次调用另一个函数,该函数调用....
    底线:当您有 2 个从一开始就相互依赖的类 (__construct) 时,您的设计可能存在缺陷。

    按照您定义这两个构造函数的方式,您将永远无法创建类的实例。仅仅是因为您需要同时实例化两个类。
    你不能,你只是不能那样做。

    试试这个:

    class A
    {
        public $b = null;
        public function __construct(B $b = null)
        {
            $this->b = $b;
        }
        public function setB(B $b = null)
        {
            if ($b === null)
            {
                $b = new B($this);//pass A here
            }
            $this->b = $b;
            return $this;
        }
    }
    class B
    {
        public $a = null;
        public function __construct(A $a = null)
        {
            $this->setA($a);
        }
        public function setA(A $a = null)
        {
            if ($a === null)
            {
                $a = new A($this);//pass B here
            }
            $this->a = $a;
            return $this;
        }
    }
    

    通过将构造函数参数的默认值设置为null,传递一个实例就变成了可选,所以现在你可以这样做了:

    $a = new A;
    $b = new B($a);
    //or even:
    $bFromA = $a->b;
    

    顺便说一句:总是事先声明你的属性。 It'll speed up your classes.

    就个人而言,我会使用 getter setter,并延迟加载依赖项,但我会保持构造函数不变:

    class A
    {
        //protected, or private. Access this via getter/setter
        protected $b = null;
        public function __construct(B $b = null)
        {
            $this->setB($b);
            return $this;
        }
        //setter, allows injection later on
        public function setB(B $b = null)
        {
            $this->b = $b;//allow to set to null
            return $this;
        }
        //getter, lazy-loader:
        public function getB()
        {
            if ($this->b === null)
            {//create new instance, if b isn't set
                $this->setB(
                    new B($this)
                );
            }
            return $this->b;
        }
    }
    class B
    {
        protected $a = null;
        public function __construct(A $a = null)
        {
            $this->setA($a);
            return $this;
        }
        public function setA(A $a = null)
        {
            $this->a = $a;
            return $this;
        }
        public function getA()
        {
            if ($this->a === null)
            {
                $this->setA(
                    new A($this)
                );
            }
            return $this->a;
        }
    }
    

    使用疙瘩:

    $c['aService'] = function($c)
    {
        return new A;
    };
    $c['bService'] = function($c)
    {
        return new B;
    };
    $b = $c->bService;
    $b->getA();//works just fine
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-29
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      • 2013-05-08
      • 1970-01-01
      相关资源
      最近更新 更多