我有两个相互依赖的课程:
class A
{
public function __construct(B $b)
{
$this->b = $b;
}
}
class B
{
public function __construct(A $a)
{
$this->a = $a;
}
}
我需要像这样把它们包裹起来:
$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!
有没有办法在没有骑车的情况下达到这种交叉依赖性?或者我只能使用单向依赖?
答案 0 :(得分:1)
这让我想起 baboushka的
当然,你必然会在这里得到无限的递归。两个函数互相调用,每次返回一个新实例,即将调用的返回值传递给它们的函数计数器部分,然后再调用该函数,再次调用另一个函数,调用....
结论:当你从一开始就有两个相互依赖的类时(__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;
BTW:总是事先声明你的属性。 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;
}
}
使用Pimple:
$c['aService'] = function($c)
{
return new A;
};
$c['bService'] = function($c)
{
return new B;
};
$b = $c->bService;
$b->getA();//works just fine