Recursive classes ... possible bug?

php.internals

Mark Sanders

19 years ago
Dear internals, I stumbled upon the following odd error message from PHP which I was not expecting. Here is a small example that triggered the error with 5.2.2, 5.2.3 and a php5.2-200706052030 snapshot. <?php class class1{ public $c2; function __construct($c2){ $this->c2 = $c2; } } class class2{ public $c1; function setC1($c1){ $this->c1 = $c1; } function test(){ echo $this == $this->c1->c2?'equals':'not equals'; // Somehow this if statement triggers the error. } } $tt = new class2(); $t = new class1($tt); $tt->setC1($t); var_dump($t); $tt->test(); ?> I get the error: Fatal error: Nesting level too deep - recursive dependency? in /home/cyanox/DEV/test_object_recursion.php on line 15 Although it is obvious that there is a recursion I think this simple example should work without error. Greetings, Mark Sanders.

Antony Dovgal

19 years ago
On 06.06.2007 01:10, mark@cyanox.nl wrote:
> <?php > class class1{ > public $c2; > function __construct($c2){ > $this->c2 = $c2; > } > } > > class class2{ > public $c1; > function setC1($c1){ > $this->c1 = $c1; > } > function test(){ > echo $this == $this->c1->c2?'equals':'not equals'; // Somehow this > if statement triggers the error. > } > } > > > $tt = new class2(); > $t = new class1($tt); > $tt->setC1($t); > var_dump($t); > $tt->test(); > ?> > > I get the error: > > Fatal error: Nesting level too deep - recursive dependency? in > /home/cyanox/DEV/test_object_recursion.php on line 15
$t->$tt->$t->$tt->$t->$tt->$t->$tt->$t->$tt->$t and so on. So you get endless recursion when comparing the objects.
> Although it is obvious that there is a recursion I think this simple > example should work without error.
Sure, if you have any proposals/ideas - feel free to share them.
-- Wbr, Antony Dovgal

Mark Sanders

19 years ago
Antony Dovgal wrote:
> On 06.06.2007 01:10, mark@cyanox.nl wrote: >> <?php >> class class1{ >> public $c2; >> function __construct($c2){ >> $this->c2 = $c2; >> } >> } >> >> class class2{ >> public $c1; >> function setC1($c1){ >> $this->c1 = $c1; >> } >> function test(){ >> echo $this == $this->c1->c2?'equals':'not equals'; // Somehow >> this if statement triggers the error. >> } >> } >> >> >> $tt = new class2(); >> $t = new class1($tt); >> $tt->setC1($t); >> var_dump($t); >> $tt->test(); >> ?> >> >> I get the error: >> >> Fatal error: Nesting level too deep - recursive dependency? in >> /home/cyanox/DEV/test_object_recursion.php on line 15 > > $t->$tt->$t->$tt->$t->$tt->$t->$tt->$t->$tt->$t and so on. > So you get endless recursion when comparing the objects. > >> Although it is obvious that there is a recursion I think this simple >> example should work without error. > > Sure, if you have any proposals/ideas - feel free to share them. >
Actually theoretically it should not give an error. I just stumbled upon this odd behavior when doing something very odd which would not work anyway so I can't really think of a situation where the correct behavior would be needed. Anyway the following also gives the error. <?php class class1{ public $c2; function __construct($c2){ $this->c2 = $c2; } } class class2{ public $c1; function test(){ $this == $this->c1; // no error. $this == $this; // errors. } } $tt = new class2(); $t = new class1($tt); $tt->c1 = $t; $tt == $t; // no error. //$t == $t; // errors. //$tt == $tt; // errors. $tt->test(); // errors. ?>

Antony Dovgal

19 years ago
On 06.06.2007 02:20, mark@cyanox.nl wrote:
>>> Fatal error: Nesting level too deep - recursive dependency? in >>> /home/cyanox/DEV/test_object_recursion.php on line 15 >> >> $t->$tt->$t->$tt->$t->$tt->$t->$tt->$t->$tt->$t and so on. >> So you get endless recursion when comparing the objects. >> >>> Although it is obvious that there is a recursion I think this simple >>> example should work without error. >> >> Sure, if you have any proposals/ideas - feel free to share them. >> > Actually theoretically it should not give an error.
Why? The behavior is quite clear - if the objects are instances of the same class, we have no other way to compare them but to compare their properties, this also applies to properties' properties and properties' properties' properties etc.
> I just stumbled upon > this odd behavior when doing something very odd which would not work > anyway so I can't really think of a situation where the correct behavior > would be needed. Anyway the following also gives the error. > > <?php > class class1{ > public $c2; > function __construct($c2){ > $this->c2 = $c2; > } > } > > class class2{ > public $c1; > function test(){ > $this == $this->c1; // no error.
Right. $this and $this->c1 are class2 and class1, no need even to look at the properties to say that they are not equal.
> $this == $this; // errors.
This is what I described earlier. If you have any ideas on how to improve it - I'd be happy to hear them.
-- Wbr, Antony Dovgal

Richard Lynch

19 years ago
On Tue, June 5, 2007 4:10 pm, mark@cyanox.nl wrote:
> Dear internals, > > I stumbled upon the following odd error message from PHP which I was > not > expecting. > > Here is a small example that triggered the error with 5.2.2, 5.2.3 and > a > php5.2-200706052030 snapshot. > > <?php > class class1{ > public $c2; > function __construct($c2){ > $this->c2 = $c2; > } > } > > class class2{ > public $c1; > function setC1($c1){ > $this->c1 = $c1; > } > function test(){ > echo $this == $this->c1->c2?'equals':'not equals'; // Somehow this > if statement triggers the error. > } > } > > > $tt = new class2(); > $t = new class1($tt); > $tt->setC1($t); > var_dump($t); > $tt->test(); > ?> > > I get the error: > > Fatal error: Nesting level too deep - recursive dependency? in > /home/cyanox/DEV/test_object_recursion.php on line 15 > > Although it is obvious that there is a recursion I think this simple > example should work without error.
I also don't see why it would recurse infinitely... Seems like it should be pretty straight-forward, unless I'm missing something...
-- Some people have a "gift" link here. Know what I want? I want you to buy a CD from some indie artist. http://cdbaby.com/browse/from/lynch Yeah, I get a buck. So?

Paweł Stradomski

19 years ago
mark@cyanox.nl wrote:
> Dear internals, > > I stumbled upon the following odd error message from PHP which I was not > expecting. > function test(){ > echo $this == $this->c1->c2?'equals':'not equals'; // Somehow this
Use === (shallow test - returns true iff the variables refer to the same instance) instead of == (deep comparision - member-by-member). AFAIK this behaviour was introduced in 5.2 or 5.1 - well, just another BC break.
-- Paweł Stradomski

Mark Sanders

19 years ago
Paweł Stradomski wrote:
> mark@cyanox.nl wrote: > >> Dear internals, >> >> I stumbled upon the following odd error message from PHP which I was not >> expecting. >> function test(){ >> echo $this == $this->c1->c2?'equals':'not equals'; // Somehow this >> > > Use === (shallow test - returns true iff the variables refer to the same > instance) instead of == (deep comparision - member-by-member). >
Still in theory it should not produce an error.
> AFAIK this behaviour was introduced in 5.2 or 5.1 - well, just another BC > break.
Actually PHP4 also bombs out with the same error so it is afaik not a BC break.

Robert Deaton

19 years ago
On 6/5/07, mark@cyanox.nl <mark@cyanox.nl> wrote: > Paweł Stradomski wrote: > > mark@cyanox.nl wrote: > > > >> Dear internals, > >> > >> I stumbled upon the following odd error message from PHP which I was not > >> expecting. > >> function test(){ > >> echo $this == $this->c1->c2?'equals':'not equals'; // Somehow this > >> > > > > Use === (shallow test - returns true iff the variables refer to the same > > instance) instead of == (deep comparision - member-by-member). > > > Still in theory it should not produce an error. Yes, it should. == is going to test all the properties of the object against each other. So to compare. $this == $this->c1->c2, it will compare $this->c1 == $this->c1->c2->c1, which will in turn compare $this->c1->c2 == $this->c1->c2->c1->c2, which in turn compares $this->c1->c2->c1 == $this->c1->c2->c1->c2->c1 And so on. -- --Robert Deaton

Daniel Penning

19 years ago
Paweł Stradomski schrieb:
> mark@cyanox.nl wrote: > >> Dear internals, >> >> I stumbled upon the following odd error message from PHP which I was not >> expecting. >> function test(){ >> echo $this == $this->c1->c2?'equals':'not equals'; // Somehow this >> > > Use === (shallow test - returns true iff the variables refer to the same > instance) instead of == (deep comparision - member-by-member). > > AFAIK this behaviour was introduced in 5.2 or 5.1 - well, just another BC > break.
Checking if the reference is equal and then doing the member-by-member comparison if they differ would prevent too deep recursion in most cases.

Christian Schneider

19 years ago
Daniel Penning wrote:
> Checking if the reference is equal and then doing the member-by-member > comparison if they differ would prevent too deep recursion in most cases.
That would solve this particular case (and might be worth doing for performance reasons anyway I'd say) but won't solve the general problem. Imagine comparing o1->o2->o1 (object 1 having a reference to object 2 which in turn has a reference back to object 1) with o3->o4->o3. You'd still get the same result as now (nesting too deep) and there is no easy way around it. - Chris

M. Sokolewicz

19 years ago
Christian Schneider wrote:
> Daniel Penning wrote: >> Checking if the reference is equal and then doing the member-by-member >> comparison if they differ would prevent too deep recursion in most cases. > > That would solve this particular case (and might be worth doing for > performance reasons anyway I'd say) but won't solve the general problem. > Imagine comparing o1->o2->o1 (object 1 having a reference to object 2 > which in turn has a reference back to object 1) with o3->o4->o3. You'd > still get the same result as now (nesting too deep) and there is no easy > way around it. > > - Chris
It might just be me, but I thought there was a student with a google summer of code project who was working on circular references and how to properly free memory for them. Perhaps some of the algorithms devised for that could be used to resolve problems as noted above? - Tul