You are here: Re: [PHP] references, circular references, oop, and garbage collection in PHP5 « PHP « IT news, forums, messages
Re: [PHP] references, circular references, oop, and garbage collection in PHP5

Posted by Alan Pinstein on 12/08/05 04:30

Hey Ray-

Thanks for the link!

Actually, the article didn't help directly, but it did spark an idea.

My main problem all along was trying to get a true reference to
$this. For some reason reading the article led me to try "$this-
>this", which works, to my surprise!

So, I now have a complete solution to my problem.... code follows...

ONE QUESTION REMAINS: is what I'm doing intended / publicly exposed
behavior, or am I hacking and at risk of failure in future versions?

Thanks,
Alan

<?php

/**
* Playing around with proper reference counting of nested objects in
PHP.
*
* The proper way to handle refCounting of nested objects is to have
parents "retain" their kids, and have the kids use "weak references"
to the parent.
*
*/

$mem0 = memory_get_usage();

for ($i=0;$i<10;$i++) {
$a = new A;
$b = new B;
$a->addB($b);
$b = NULL; // kill the ref from a to b so as to GC b. If
we've done things right, b will still exist and the next line will
not fail.
$a->printBs();
$a = NULL; // kill the local ref to a, which should be the
only ref-counted ref to a if we've done things right; this should
cause a (and thus b) to be gc'd NOW.
}

print "Leaked: " . (memory_get_usage() - $mem0) . "\n";
print "Done\n";
exit;

class A
{
public $b = array();
private $memWaste;

function __construct()
{
$this->memWaste = "";
for ($i = 0; $i < 1000; $i++) {
$this->memWaste .= "1234567890";
}
print "new A{$this}\n";
}
function __destruct()
{
print "kill A{$this}\n";
}

// add a child B to our list. We want a ref-counted instance here.
function addB($b)
{
$this->b[] = $b; // refCounted desired in parent->child link
$b->setA($this->this); // so, this is apparently how you
access a true reference to $this, because &$this doens't work.
}

function printBs()
{
foreach ($this->b as $b) {
$b->sayHi();
}
}
}

class B
{
public $a;
private $memWaste;
function __construct()
{
$this->memWaste = "";
for ($i = 0; $i < 1000; $i++) {
$this->memWaste .= "1234567890";
}
print "new B{$this}\n";
}
function __destruct()
{
print "kill B{$this}\n";
}
// refCount NOT desired in child->parent link, so use ref vars
function setA(&$a)
{
$this->a = &$a;
}

function sayHi()
{
print "HI from {$this}\n";
}
}
?>


On Dec 6, 2005, at 7:10 PM, Ray Hauge wrote:

> I am uncertain on this, but I believe that the $this variable is
> already just a reference to the class you are calling it from.
> Then passing the reference by-reference to the addParent() method
> of the Child class could be what is causing your issue. I'd be
> curious to see what would happen if you took out the pass-by-
> reference and instead pass-by-value for the addParent() method.
> Then again, that doesn't particularly sound correct either.
>
> This link might help. They cover a lot of advanced reference usage
> for PHP.
>
> http://www.onlamp.com/pub/a/php/2002/09/12/php_foundations.html
>
> Alan Pinstein wrote:
>
>> So.. I am having PHP5 memory management problems.
>>
>> They are similar to those described in this thread:
>>
>> http://aspn.activestate.com/ASPN/Mail/Message/php-Dev/1555640
>>
>> (so maybe this question belongs on php-dev but I figured I'd try
>> here first... seems like a userland question)
>>
>> Basically I have an object model to represent db objects, and I
>> am bulk-loading the objects via some PHP scripts. Sadly the
>> scripts consume unbounded memory because of this problem.
>>
>> I have done a lot of programming in C++ and Obj-C and the normal
>> way to handle circular references is to have parents
>> "retain" (keep ref- counted links) to their kids, and have the
>> kids have "weak references" (non-ref-counted) links to their
>> parents. This way, when the parent is no longer used, it will
>> automatically 0-out the ref counts to all children it links too
>> and things GC correctly.
>>
>> Now, how to do this in PHP?
>>
>> Well, there are no "documented" weak references. However, I
>> figured out by trial that if you obtain a php-reference to an
>> object, it doesn't bump the refcount.
>>
>> Question #1: Is the fact that references to objects in the form
>> $objRef = &$obj don't bump the refcount of $obj an intended
>> behavior that can be counted on? If so, cool!
>>
>> So, now that we have a way to do weak references, we should be
>> able to implement a reasonable memory management scheme for
>> parent-child objects.
>>
>> Normally from the client side the interface should look something
>> like:
>>
>> $parent = new Parent();
>> $child = new Child();
>> $parent->addChild($child);
>>
>> Where parent can have 0,n children and child can have 0,1 parent.
>>
>> And all of parent's internal links to child should be refcounted,
>> and the internal links from child to parent are weak (not ref-
>> counted).
>>
>> So based on the above discovery about references, I tried to
>> implement this as such:
>>
>> class Parent
>> {
>> public $children = array();
>>
>> // add a child to our list. We want a ref-counted link here.
>> function addChild($child)
>> {
>> $this->children[] = $child; // refCounted desired in
>> parent->child link
>> $child->setParent($this);
>> }
>> }
>>
>> class Child
>> {
>> public $parent;
>>
>> // set the parent object. We want a non-ref-counted link here.
>> function setParent(&$parent)
>> {
>> // refCount NOT desired in child->parent link
>> $this->parent = &$parent;
>> }
>> }
>>
>> Now, you'd expect this would work, but it doesn't. On a hunch, I
>> changed the client code to:
>>
>> $parent = new Parent();
>> $child = new Child();
>> $parent->addChild($child);
>> $child->setParent($child); // new line here - you can
>> successfully create a reference to the object when not passed in
>> as $this
>>
>> Now, this works! However, it's not practical. The setParent call
>> should work from within the parent object....
>>
>> So what I figured out is that $this is a "pseudo variable"
>> according to the docs, but I don't know what that means.
>> Empirically I have figured out that it means you cannot create a
>> reference to it.
>>
>> Is this a feature or a bug? What's the workaround?
>>
>> This is a serious problem for PHP scripts that need to do things
>> that require large amounts of memory.
>>
>> Please advise.
>>
>> Thanks,
>> Alan
>>
>
> --
> PHP General Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
>

 

Navigation:

[Reply to this message]


Удаленная работа для программистов  •  Как заработать на Google AdSense  •  England, UK  •  статьи на английском  •  PHP MySQL CMS Apache Oscommerce  •  Online Business Knowledge Base  •  DVD MP3 AVI MP4 players codecs conversion help
Home  •  Search  •  Site Map  •  Set as Homepage  •  Add to Favourites

Copyright © 2005-2006 Powered by Custom PHP Programming

Сайт изготовлен в Студии Валентина Петручека
изготовление и поддержка веб-сайтов, разработка программного обеспечения, поисковая оптимизация