# Recursive classes ... possible bug?

- Thread: https://externals.io/message/30084
- Original archive: https://news-web.php.net/php.internals/30084
- Started by mark@cyanox.nl on 2007-06-05T21:10:55+00:00
- Messages: 12
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #30084 — mark@cyanox.nl — 2007-06-05T21:10:55+00:00

URL: https://externals.io/message/30084#30084

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.

---

## #30088 — Antony Dovgal — 2007-06-05T21:19:19+00:00

URL: https://externals.io/message/30084#30088 · In reply to: #30084

> <?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

---

## #30092 — Richard Lynch — 2007-06-05T21:46:28+00:00

URL: https://externals.io/message/30084#30092 · In reply to: #30084

> 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?

---

## #30097 — pstradomski@gmail.com — 2007-06-05T22:15:51+00:00

URL: https://externals.io/message/30084#30097 · In reply to: #30084

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

---

## #30098 — mark@cyanox.nl — 2007-06-05T22:20:47+00:00

URL: https://externals.io/message/30084#30098 · In reply to: #30088

Antony Dovgal wrote:
> 
> > […]
>
> $t->$tt->$t->$tt->$t->$tt->$t->$tt->$t->$tt->$t and so on.
> So you get endless recursion when comparing the objects.
>
> > […]
>
> 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.
?

---

## #30101 — Robert Deaton — 2007-06-06T00:30:23+00:00

URL: https://externals.io/message/30084#30101

> Paweł Stradomski wrote:
> > […]
> 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

---

## #30102 — Antony Dovgal — 2007-06-06T06:10:04+00:00

URL: https://externals.io/message/30084#30102 · In reply to: #30098

> > […]
> 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

---

## #30112 — Christian Schneider — 2007-06-06T10:32:56+00:00

URL: https://externals.io/message/30084#30112

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

---

## #30113 — M. Sokolewicz — 2007-06-06T11:52:32+00:00

URL: https://externals.io/message/30084#30113 · In reply to: #30112

Christian Schneider wrote:
> Daniel Penning wrote:
> > […]
> 
> 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

---

## #30114 — Antony Dovgal — 2007-06-06T12:03:48+00:00

URL: https://externals.io/message/30084#30114

> > […]
> Well yes but in this case they are the same instance. Comparing the 
> properties is then useless since they will always be the same.
>
> Well there could be made a check to see if the objects are the same 
> instance (like with ===) before actually checking the properties.

Hm.. I was actually a bit surprised to see that we don't do "===" before doing "==" on objects.
That would of course prevent the recursion in case of comparing an object to itself.

I committed a patch minute ago, but it obviously won't change the case when the objects are 
different and contain circular references. 

Anyway, thanks a lot for pointing this out.

-- 
Wbr, 
Antony Dovgal

---

## #30115 — mark@cyanox.nl — 2007-06-06T13:04:07+00:00

URL: https://externals.io/message/30084#30115 · In reply to: #30114

Antony Dovgal wrote:
> 
> > […]
>
> Hm.. I was actually a bit surprised to see that we don't do "===" 
> before doing "==" on objects.
> That would of course prevent the recursion in case of comparing an 
> object to itself.
>
> I committed a patch minute ago, but it obviously won't change the case 
> when the objects are different and contain circular references.
> Anyway, thanks a lot for pointing this out.
>
Thanks and keep up the good work!

Greetings,

Mark Sanders.

---

## #30118 — Greg Beaver — 2007-06-06T16:56:53+00:00

URL: https://externals.io/message/30084#30118 · In reply to: #30114

Antony Dovgal wrote:
> 
> > […]
> 
> Hm.. I was actually a bit surprised to see that we don't do "===" before
> doing "==" on objects.
> That would of course prevent the recursion in case of comparing an
> object to itself.
> 
> I committed a patch minute ago, but it obviously won't change the case
> when the objects are different and contain circular references.
> Anyway, thanks a lot for pointing this out.

This is especially surprising because I mentioned this in Oct. 2004
(http://groups.google.com/group/mailing.www.php-dev/msg/c3bcb36e5c6eb07b?dmode=source&hl=en)

and Andi took this on:

http://groups.google.com/group/mailing.www.php-dev/msg/4429a975af7e4924?dmode=source&hl=en

then claimed to have fixed it:

http://groups.google.com/group/mailing.www.php-dev/msg/6ad9e1b23bf4862e?dmode=source&hl=en

However, a scan of all CVS commits between Oct. 19-21 at news.php.net
(this took a while) revealed no commits at all, and looking at
zend_operators.c in both Zend/ and ZendEngine2 reveals no commits by
Andi anywhere near this time.

Sounds like it just slipped through the cracks somehow.

Greg
