Re: destruction of cross-referenced objects

From: Date: Wed, 06 Dec 2006 13:34:29 +0000
Subject: Re: destruction of cross-referenced objects
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to internals+get-26813@lists.php.net to get a copy of this message
Hi, I think having to extend a base class is not a good idea. First of all you deprive yourself of extending a class of a library you haven't written (like something from Zend Framework or PEAR). Second it puts a huge constraint on the code of the users of your library, because any class they write needs to extend your base class. A slightly better solution would be to use an interface. A solution like this forces you to have some kind of framework with general interfaces/classes used in all of your libraries. To my opinion a user shouldn't have to set up an elaborate framework in PHP to prevent memory leaks. I've heard some good comments, but no real good solutions. So I think I should just write the destroy function. I hope it will find its way into PHP or (even better) that someone can find a way to prevent these memory leaks. Best regards, Arnold Richard Quadling schreef:
In user land, I have an abstract_object like this (http://rquadling.php1h.com/abstract_object.html). I've come from a Delphi environment so some of the code you see is based upon some of the ideas I see in the TObject class. There are some comments, but the basic idea is there. On 05/12/06, Arnold Daniels <info@adaniels.nl> wrote:
Richard Lynch schreef:
On Mon, December 4, 2006 7:21 pm, Arnold Daniels wrote:
I'm struggling with the problem that cross-referenced objects don't get destroyed. I can off course write a method to break the cross-reference, but that's kind of a pain in the butt, especially if the cross-reference is not strait forward.
Seems to me that a simple unset() on the data members in userland coude so PHPs refcount is decremented ought to do it... If a user creates a monstrous data structure and doesn't prune it, how much responsibility can PHP take for that? But maybe I'm just being naive.
I myself run into problems when implementing parent/child relationships within object. I probably use PHP a bit different than the regular user and therefor run into different problems, but with more elaborate frameworks being build, I think more people will run into these kind of problems. Think about a DOM implementation fully in PHP (I'm not building that, but just to give you an idea). Using uset() on each child wouldn't do much good, since each also holds a parent/child relationship with its children and therefor the child is not destroyed, meaning the parent is not destroyed. To overcome this you need implement a method destroy(), which runs through all property to see if it is a DOM object and call the destroy() on it. But now imagine another class which has properties with objects of all kinds of classes, some of which have parent/child relationships. Now you need all these classes to implement some sort of destroyable interface. I don't really like a solution like this. With the destroy function you would still need to walk through the children and call destroy forcing an unset in the destructor of the class, but it's a step up.
To solve this I'm thinking of building one of 2 thing: 1.) Write a destroy() function which works much like a close function on a recourse, changing the object to a zval of type 'unknown'. 2.) Specify that a property of an object does not count for the reference count of a zval.
I don't think this is a Good Idea... Seems like it would be WAY too easy for userland code to end up with a 0 for the refcount and then GC kicks in.
Yes, that is what I want. If the parent object is unset, the parent property of the child object should be set to unknown or something. But I guess that the memory is freed and the zval isn't set to unknown and you would just get unexpected results.
3.) Write code to find cross-references and destroy the objects
still.
The first solution should be quite easy to implement, but you need to call destroy() to free the object, introducing the whole alloc/free responsibility thing to PHP.
Just use unset() for this, rather than introduce yet another confusing function.
The second solution would require some extra keyword within the
class,
but require no special code within the code using the object.
Though I
wouldn't have a clue how how to implement this or what would be the consequences.
I don't think the third solution is really possible or would at least cause performance problems.
Finding a "dead branch" of cyclic structures is basic CS stuff. Add a second temp "refcount" and start walking the graph. Either you end up with something known to be in the GLOBAL scope, or you don't. It can take a long time, depending on the size of the graph, but it's just pointer-chasing and integer arithmetic, so shouldn't be THAT slow.
I don't really see this solution. I wouldn't unnecessarily find anything in the GLOBAL scope. When using unset or returning from a function, a check should be made to find if the variable is used within the scope of the call stack, global or statically. To my knowledge (which is small on the PHP internals subject) it is only possible to see how many references to the object there are, not where there references are. Thank you for commenting on my e-mail. I hope you understand where I'm coming from with this problem and understand why unset will not do. I hope that you or perhaps someone else might have some other comments or solutions I haven't yet thought of. Best regards, Arnold


« previous php.internals (#26813) next »