简体   繁体   中英

PHP pimple cross dependency

I have two classes which depending on each other:

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

And I need to wrap them through Pimple like this:

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

But unfortunately I get cycling:

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

Is there any way to reach this cross-dependency without cycling? Or I can use only unidirectional dependencies?

This reminds me of baboushka's

Of course you're bound to get infinite recursion here. Both functions call each other, each time returning a new instance, that is passed the return value of the call to their function-counter part, which in turn calls the function again, which calls the other function again, which calls....
Bottom line: when you have 2 classes that depend on each other from the get-go ( __construct ), your design is probably flawed.

The way you've defined both constructors, you'll never be able to create an instance of the classes. Simply because you need to instantiate both classes at the same time.
You can't, you simply cannot do that.

Try this:

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

By setting the default value of the constructor arguments to null , passing an instance has become optional , so now you can do this:

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

BTW: always declare your properties beforehand. It'll speed up your classes .

Personally, I'd use a getter and a setter, and lazy-load the dependency, but I would keep the constructor as is:

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

Using Pimple:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM