weakreference_bc is a fork of the unmaintained https://pecl.php.net/weakref PECL. The weakreference_bc
PECL changes the API to provide polyfills for WeakReference/WeakMap
A weak reference provides a gateway to an object without preventing that object from being collected by the garbage collector (GC). It allows to associate information to volatile object. It is useful to associate metadata or cache information to objects. Indeed, the cache entry should not be preventing the garbage collection of the object AND the cached info when the object is no longer used.
The WeakReference class is a simple class that allows to access its referenced object as long as it exists. Unlike other references, having this WeakReference object will not prevent the object to be collected.
See https://www.php.net/manual/en/class.weakreference.php
<?php
class MyClass {
public function __destruct() {
echo "Destroying object!\n";
}
}
$o1 = new MyClass;
$r1 = WeakReference::create($o1);
if (is_object($r1->get())) { // It does have a reference
echo "Object still exists!\n";
var_dump($r1->get());
} else {
echo "Object is dead!\n";
}
unset($o1);
if (is_object($r1->get())) { // It doesn't have a reference
echo "Object still exists!\n";
var_dump($r1->get());
} else {
echo "Object is dead!\n";
}
?>
The WeakMap class is very similar to WeakReference, only that it also allows to associate data to each object. When the target object gets destroyed, the associated data is automatically freed.
This is similar to https://www.php.net/manual/en/class.weakmap.php (but currently implements Iterator instead of IteratorAggregate)
<?php
$wm = new WeakMap();
$o = new StdClass;
class A {
public function __destruct() {
echo "Dead!\n";
}
}
$wm[$o] = new A;
var_dump(count($wm)); // int(1)
echo "Unsetting..\n";
unset($o); // Will destroy the 'new A' object as well
echo "Done\n";
var_dump(count($wm)); // int(0)
?>
Iterating over WeakMap provides access to both the key (the reference) and the value:
<?php
$wm = new WeakMap();
$wmk = new StdClass;
$wmv = new StdClass;
$wm[$wmk] = $wmv;
foreach($wm as $k => $v) {
// $k == $wmk
// $v == $wmv
}
?>
Prior to php 7.0.3, using an object with WeakReference::create
or as a key in an entry of of WeakMap
would cause this to change the value of spl_object_hash
and SplObjectStorage::getHash
.
A userland polyfill for WeakMap for php 7.4+ is https://github.com/BenMorel/weakmap-polyfill . That library offers a compatible implementation with the native WeakMap, but:
- slower
- whose values are not removed as soon as the object key is destroyed, but when you use the WeakMap again (eventually triggering housekeeping); note that this affects when object destructors are called as well