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
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php