In PHP 7.4 I noticed the number of collected cycles returned by gc_collect_cycles is always zero when there is a destructor
method in a cyclic referenced object.
class A {
public function __destruct() {
}
}
gc_disable();
$a1 = new A;
$a2 = new A;
$a1->ref = $a2;
$a2->ref = $a1;
$a1 = $a2 = NULL;
echo('removed cycles: '.gc_collect_cycles()); // Output: removed cycles: 0
When I remove the __destruct
method the output is:
removed cycles: 2
You can see this behavior started as of PHP 7.4.0beta4
What is going on here ? Are garbage cycles get collected in the destructor even when GC is disabled?
Since PHP 7.4, the initial garbage collection run will only call destructors on objects that have them, and the actual destruction of the object is deferred to the next GC run. You can see this if you perform two calls to gc_collect_cycles(): https://3v4l.org/0LIVn
The reason for this behavior is that destructors can introduce additional references to the object, such that it is no longer valid to destroy it. Previous versions used an unreliable heuristic to detect this case. PHP 7.4 will instead delay destruction to a separate GC run.