PHP 5 garbage collection

The object-oriented features of PHP 5 are a really positive step forward
for the language. One of the biggest improvements, to my mind, is that
you no longer have to choose to pass things around by reference with a
liberal smattering of ‘&’ symbols: references are now the default way of
passing objects.

One problem I have come across, though, is that the reference counting
feature of PHP’s garbage collection
(http://www.zend.com/zend/art/ref-count.php) means that objects with
mutual references are not deleted even when I thought the object was out
of existence. E.g:

class ParentObject()
{
  protected $childObject;

  function __construct()
  {
    $this->childObject = new ChildObject($this);
  }
}

class ChildObject()
{
  protected $parentObject;

  //Pass in a reference to the parent
  //object and store it internally
  function __construct($parentObject)
  {
    $this->parentObject = $parentObject;
  }
}

Then if I call $foo = new ParentObject(); then it automatically creates
a child object with a reference to the parent. The parent also keeps a
reference to its child. If I then unset($foo); the two objects are still
referencing each other and so are not deleted. The only way I’ve found
to clear this is to create a new method (which I call destroy()) to
delete references to the child. Calling destroy() on the parent first
calls destroy() on its child, which dereferences the parent, and then
the parent dereferences the child. So the classes are now:

class ParentObject()
{
  protected $childObject;

  function __construct()
  {
    $this->childObject = new ChildObject($this);
  }

  public function destroy()
  {
    $this->childObject->destroy();
    unset($this->childObject);
  }
}

class ChildObject()
{
  protected $parentObject;

  //Pass in a reference to the parent object
  //and store it internally
  function __construct($parentObject)
  {
    $this->parentObject = $parentObject;
  }

  public function destroy()
  {
    unset($this->parentObject);
  }
}

And I have to call

$foo->destroy();
unset($foo);

To clear the thing out completely.

This can cause a number of problems which I won’t go into in detail here
(they occur in more complex design patterns), but suffice to say that
there are a number of occassions where I don’t necessarily want to
destroy a child at the same time as a parent, or vice-versa. E.g. a
child references multiple parents. The end result is that I’m writing
code to deal with garbage collection where it is having a big effect on
memory and just leaving it out where it doesn’t seem to make as much
difference. This suffices for a known set of data but doesn’t feel very
satisfactory in terms of future-proofing.

I would appreciate it if anyone else has a better way of doing things.

0 thoughts on “PHP 5 garbage collection”

  1. I take your point and had considered it but (and I haven’t actually tried this) I wasn’t sure if I called __destruct deliberately then it would be called again when the object was actually destroyed.The main reason I initially made my own method, though, was so that I could put some code in __destruct to flag that the object had actually been destroyed – some objects were destroying themselves fine, others weren’t and __destruct seemed the best way to debug when an object actually disappeared.

  2. The destructor isn’t called until the object is being destroyed. Because of the existing references, the object isn’t being destroyed until the end of the request and therefore putting this code in the destructor doesn’t work.

  3. Wow, someone else actually trying to memory manage parent-child relationships in PHP!So, I have been grappling with this problem while working on Propel. I actually found a way to create non-refcounted references in PHP5… if you $a = &$b; where $b is an object, $a points to it, but doesn’t bump the refcount. Which is half of the solution…The other problem I’ve found though is that you can’t create a non-refcounted reference to $this, so in your function like $child->setParent($this) it doesn’t work. It does work if you $child->setParent($parent) though, and then you don’t have to explicitly call destroy() methods.I am trying to find a way around the $this problem as we speak….-Alan

  4. In reply to alan, apparent you can use $this->this to get a non ref-counted reference to a class. I have this recursive reference problem, and thats one way around it, althou there is a severe lack of documentation about $this->thishttp://www.zend.com/zend/week/week266.phpOnly thing is i have no idea what version of php5 these guys are using, 5.1.2 that i’m using seems to be missing this functionality.

Leave a Reply

Your email address will not be published. Required fields are marked *