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