Edit report at https://bugs.php.net/bug.php?id=60087&edit=1

 ID:                 60087
 Comment by:         luke at cywh dot com
 Reported by:        luke at cywh dot com
 Summary:            release() function and __release() method
 Status:             Open
 Type:               Feature/Change Request
 Package:            Class/Object related
 PHP Version:        5.3.8
 Block user comment: N
 Private report:     N

 New Comment:

Here's another demo that demonstrates the exact functionality I describe:

gc_disable();

class A {
        function __construct() {
                $this->b = new B($this);
        }

        // function __release() {
        //      unset($this->b);
        // }
}

class B {
        function __construct($parent = NULL) {
                $this->parent = $parent;
        }
}

function release(&$var) {
        if(is_object($var)){
                if(method_exists($var, '__release')) {
                        $var->__release();      
                }
                else {
                        foreach(array_keys(get_object_vars($var)) as $k) {
                                $v = $var->$k;
                                $var->$k = NULL;
                                release($v);
                        }
                }
        }
        else if(is_array($var)) {
                foreach($var as &$c) {
                        release($c);
                }
        }

        $obj = NULL;
}

for($i = 0; $i < 1000000; $i++) {
    $a = new A();
    release($a);
}


I realize that "array_keys(get_object_vars($var))" is horrible, especially 
since 
it's limited by scope. An internal version wouldn't have this sort of 
limitation.


Previous Comments:
------------------------------------------------------------------------
[2011-10-18 19:39:30] luke at cywh dot com

Description:
------------
This is in reference to circular references, as outlined in this bug:

https://bugs.php.net/bug.php?id=33595

The "solution" in PHP 5.3 is the garbage collector, which seems to work well. 
But it's lazy, meaning it only frees memory when it has to. On a complex web 
application I came across a situation where the garbage collector didn't free 
memory like it should have. Eventually the script ran out of memory. Granted it 
got a lot farther than 5.2 did.

The most common occurrence (only?) of a circular reference is a parent and 
child 
relationship with objects. The unset() function is useless because a reference 
is held, so __destruct is never ran.

I propose an additional more aggressive function called release(). It would 
function just like unset(), but would additionally call a __release() method 
within the object allowing for cleanup before unsetting the object.

If the __release() method doen't exist perhaps PHP could unset the properties 
itself, and call __release() on any objects that may be stored in an 
array/property.

I've added a demo of how this could work. The demo is different in that it 
requires __release(). An internal solution may not.

Test script:
---------------
gc_disable();

interface Release {
        function __release();
}

class A implements Release {
        function __construct() {
                $this->b = new B($this);
        }

        function __release() {
                unset($this->b);
        }
}

function release(Release &$obj) {
        $obj->__release();
        $obj = NULL;
}

class B {
        function __construct($parent = NULL) {
                $this->parent = $parent;
        }
}

for($i = 0; $i < 1000000; $i++) {
    $a = new A();
    release($a);
}




------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=60087&edit=1

Reply via email to