Recursive references in container->member objects

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
si_davis
Forum Newbie
Posts: 3
Joined: Wed May 24, 2006 5:32 am
Location: Manchester, UK

Recursive references in container->member objects

Post by si_davis »

Hi,

I'm currently re-writing a browser-based game I maintain and develop for a fan community site. The original game was unclassed and I wanted to incorporate some of the benefits of inheritance and extension by rewriting it to use a class hierarchy.

However, I'm having trouble with an aspect of PHP references and would appreciate any pointers or explanations of why I'm seeing the behaviour described below. The closest thread I could find here is Self Referencing References, but it doesn't seem to address my specific query. For reference, this is running under PHP 4.3 - because the game is a section of a larger site which I do not control, moving up to PHP 5 is not an option at this time.


For this game, I have a number of 'agent' objects to represent players' characters, which are stored in an array which is a member of a 'battle' object. Thus the battle object 'contains' a number of agent objects, which need to be able to influence the battle object from their own methods. To accomplish this, each agent object stores a reference to the battle object which contains it. (This is the top level of the model; in the actual game, the agent objects similarly contain 'tactic' and 'weapon' objects, with references to the owning agent object.)

The following code is a minimal test case of this setup:

Code: Select all

<?php
class Container
{
	function Container()
	{
		$this->id = uniqid('');
		$this->contents = array();
	}
}

class Content
{
	function Content()
	{
		$this->id = uniqid('');
		$this->container_ref = NULL;
	}
}

// Create an instance of the Container class
$a = new Container();

// Populate the contents array with Content objects and set references to the Container object
for ($i = 0; $i < 2; $i++) {
	$a->contents[$i] = new Content();
	$a->contents[$i]->container_ref =& $a;
}

print_r($a);
?>
The print_r statement gives the following results:

Code: Select all

container Object
(
    [id] => 4474381f78ef5
    [contents] => Array
        (
            [0] => content Object
                (
                    [id] => 4474381f78f33
                    [container_ref] => container Object
                        (
                            [id] => 4474381f78ef5
                            [contents] => Array
 *RECURSION*
                        )

                )

            [1] => content Object
                (
                    [id] => 4474381f78f67
                    [container_ref] => container Object
                        (
                            [id] => 4474381f78ef5
                            [contents] => Array
 *RECURSION*
                        )

                )

        )

)
Notice that the only the contents array of the referenced Container object is picked up as being recursive. Logically, I expect the recursion tag to start at the container_ref variable of the Content object...

After searching through the PHP documentation (including comments) and various resources, I've tried setting the references inside and outside of the objects' constructors, having the constructor return a reference, setting the container_ref as a reference whilst returning a reference from the Content constructor... Nothing I've tried has made print_r recognise that the container_ref variable of each Content object is just a reference to the variable $a that it's currently printing.


Because I'm not setting references to the Container object within the Content constructor, the case as printed above does correctly reference the Container object even without returning a reference from the Content constructor. This can be checked by adding the following lines to the test case:

Code: Select all

<?php
foreach ($a->contents as $id => $obj) {
	$a->contents[$id]->container_ref->id = uniqid('');
}
print_r($a);
?>
and verifying that $a->contents[0...1]->container_ref->id is still the same as $a->id. Therefore, the code should be fine for my actual purpose, but I still want to nail this recursive reference thing. The seeming duplication of the Container object under every Content object is trivial in this case, but when the Container object has a great number of variables and contains futher arrays, printing out a representation of the populated instance for debugging become completely unworkable.

It's just the lack of recognition for the recursion at the level of Content->container_ref that's bugging me. Am I misunderstanding the way print_r figures out / displays recursion? Is this just a 'feature' of classes in PHP 4? Or is there something I can do to get the recursion recognised at the 'logical' level?


Any help appreciated! Thanks.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

print_r() in PHP4 doesn't really handle recursive structures all that well... this was brought up in a thread here some time last year. I belive PHP5 works a little differently but I'll do a little test in PHP5:

Code: Select all

Container Object
(
    [id] => 447448d709fea
    [contents] => Array
        (
            [0] => Content Object
                (
                    [id] => 447448d70f39a
                    [container_ref] => Container Object
 *RECURSION*
                )

            [1] => Content Object
                (
                    [id] => 447448d713d3d
                    [container_ref] => Container Object
 *RECURSION*
                )

        )

)
Looks better :)
User avatar
si_davis
Forum Newbie
Posts: 3
Joined: Wed May 24, 2006 5:32 am
Location: Manchester, UK

Post by si_davis »

So the model is fine, it's just print_r()'s representation of it in PHP 4 that's giving misleading info?

That's the conclusion I was heading towards having tried all the methods I could think of to jiggle with the references. Oh well, just have to keep writing dump handlers until the host site goes to PHP 5.

Thanks for your help, d11wtq!
Post Reply