Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:26829 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 96286 invoked by uid 1010); 7 Dec 2006 11:33:50 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 96271 invoked from network); 7 Dec 2006 11:33:50 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 7 Dec 2006 11:33:50 -0000 Authentication-Results: pb1.pair.com smtp.mail=info@adaniels.nl; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=info@adaniels.nl; sender-id=unknown Received-SPF: error (pb1.pair.com: domain adaniels.nl from 82.94.235.198 cause and error) X-PHP-List-Original-Sender: info@adaniels.nl X-Host-Fingerprint: 82.94.235.198 hyak.bean-it.nl Received: from [82.94.235.198] ([82.94.235.198:57710] helo=hyak.bean-it.nl) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 9C/92-13900-8DBF7754 for ; Thu, 07 Dec 2006 06:33:15 -0500 Received: from [127.0.0.1] (bean-it.xs4all.nl [213.84.27.165]) (authenticated bits=0) by hyak.bean-it.nl (8.13.4/8.13.4/Debian-3sarge3) with ESMTP id kB7BWTIw031632; Thu, 7 Dec 2006 12:32:33 +0100 Message-ID: <4577FBC4.3040909@adaniels.nl> Date: Thu, 07 Dec 2006 12:32:20 +0100 User-Agent: Thunderbird 1.5.0.8 (Windows/20061025) MIME-Version: 1.0 To: RQuadling@GoogleMail.com CC: internals@lists.php.net References: <4574C97F.8020507@adaniels.nl> <22319.204.16.229.245.1165342794.squirrel@www.l-i-e.com> <4575F689.3000709@adaniels.nl> <10845a340612060040g7b04b612vf4a89873a2478473@mail.gmail.com> <4576C6E5.301@adaniels.nl> <10845a340612070039x2aa79b0fi1e13c40e9be41299@mail.gmail.com> In-Reply-To: <10845a340612070039x2aa79b0fi1e13c40e9be41299@mail.gmail.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: by amavisd-new X-Spam-Status: No, score=3.0 required=4.0 tests=BAYES_50,URIBL_BLACK autolearn=no version=3.1.3 X-Spam-Level: *** X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on hyak.bean-it.nl Subject: Re: [PHP-DEV] destruction of cross-referenced objects From: info@adaniels.nl (Arnold Daniels) Hi, I don't think a discussion on programming methods is something for the PHP internals list. I understand how you do it, but I (and perhaps others) would like to do it differently. I have tried to explain why and I hope you understand. I would like to be able to prevent memory leaks without tricks. It's not there, so I will build it and I hope others will see the usefulness of it and perhaps even put it into PHP. Best regards, Arnold Richard Quadling schreef: > The reason I have this base class is that there is equivalent > functionality within the built in object in PHP. No concept of > ownership or relationship. > > In my rudimentary framework, nearly my components are related in some > way. VERY little stands alone. > > Therefore, for me, the base object having ownership capabilities is > perfect. > > The main advantage of having this functionality is that, in theory, > you only ever destroy 1 object. All other objects are owned and are > therefore destroyed in the correct order. > > If you notice from my code, the __destruct() method of the base object > deals with destroying all owned objects. > > > I am not sure I agree with you about having interfaces. PHP does not > allow method inclusion into a class (I cannot build a class from a set > of methods in different files). > > If PHP handled multiple inheritence, then this would be ideal, but as > far as I know only a handful of specialist languages support true MI. > I think I understand the issues that argue against it and I am not > advocating that PHP SHOULD support it, it just would be nice if it > did. It would be useful. > > An alternative way to building a deep class structure is to have a > "flattening" script. So, take the deep classes and creat squashed > classes via a script. You would have some constraints though. No > longer would every class be of type abstract_object as well as > constraints on the origin of class constants. Not an ideal solution. > > > > The basic reason I have this base class is to enforce the order of > destruction. I try very hard to make my classes no more than 3 deep, > but ownership goes WAY deep! (I have a particular instance of 23 > levels of ownership!). > > Now trying to destroy all of those objects in the right order would be > a nightmare without the base object dealing with it. > > > > As for using a third party framework (Zend / PEAR / eZ / Prado / etc), > then each would have to be examined to see if it dealt with ownership. > I would be truly surprised if it did not. > > > > > > > > On 06/12/06, Arnold Daniels wrote: >> 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 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 >> >> >> >> >> > >> > >> >> > >