44[ ![ Windows Build status] ( https://ci.appveyor.com/api/projects/status/7r07eydi6c3lj36a/branch/master?svg=true )] ( https://ci.appveyor.com/project/pinepain/php-weak )
55[ ![ GitHub license] ( https://img.shields.io/badge/license-MIT-blue.svg )] ( https://raw.githubusercontent.com/pinepain/php-weak/master/LICENSE )
66
7- This extension provides [ weak references] ( https://en.wikipedia.org/wiki/Weak_reference ) support for PHP 7 and serves
8- as a ground for other weak data structures.
7+ This extension adds [ Soft Reference] ( https://en.wikipedia.org/wiki/Weak_reference ) and
8+ [ Weak References] ( https://en.wikipedia.org/wiki/Weak_reference ) to PHP 7 and may serve as a ground for other
9+ data structures that require advanced referencing model.
910
1011
1112## Usage
@@ -14,12 +15,18 @@ as a ground for other weak data structures.
1415<?php
1516
1617use Weak\Reference;
18+ use Weak\SoftReference;
1719
18- $obj = new stdClass();
20+ $obj = new class {
21+ public function __destruct() {
22+ echo 'Destructor called', PHP_EOL;
23+ }
24+ };
1925
20- $ref = new Reference($obj, function () { echo 'Object destroyed', PHP_EOL; });
26+ $softref = new SoftReference($obj, function () { echo 'Object will be destroyed', PHP_EOL; });
27+ $weakref = new Reference($obj, function () { echo 'Object destroyed', PHP_EOL; });
2128
22- $obj = null; // outputs "Object destroyed"
29+ $obj = null; // outputs "Object will be destroyed", "Destructor called", "Object destroyed" in this specific order.
2330```
2431
2532
@@ -29,20 +36,33 @@ This extension adds `Weak` namespace and all entities are created inside it.
2936
3037There are no INI setting or constants provided by this extension.
3138
32- Brief docs about [ ` Weak\Reference ` class ] ( ./stubs/weak/Reference.php ) and [ functions] ( ./stubs/weak/functions.php )
39+ Brief docs about classes and [ functions] ( ./stubs/weak/functions.php )
3340may be seen in [ stub files] ( ./stubs/weak ) .
3441
3542Short list if what provided by this extension is:
3643
37- - ` class Weak\Reference `
38- - ` class Weak\NotifierException extend Exception `
44+ - ` abstract class Weak\AbstractReference ` * may not be subclassed directly* [ doc] ( ./stubs/weak/AbstractReference.php )
45+ - ` class Weak\SoftReference extends AbstractReference ` [ doc] ( ./stubs/weak/SoftReference.php )
46+ - ` class Weak\Reference extends AbstractReference ` [ doc] ( ./stubs/weak/Reference.php )
47+ - ` class Weak\NotifierException extend Exception ` [ doc] ( ./stubs/weak/NotifierException.php )
3948 - ` function Weak\refcounted() `
4049 - ` function Weak\refcount() `
50+ - ` function Weak\softrefcounted() `
51+ - ` function Weak\softrefcount() `
52+ - ` function Weak\softrefs() `
4153 - ` function Weak\weakrefcounted() `
4254 - ` function Weak\weakrefcount() `
4355 - ` function Weak\weakrefs() `
4456 - ` function Weak\object_handle() `
57+ - ` function Weak\is_obj_destructor_called() `
58+
59+ ### References
60+
61+ There are two type of reference provided by this extension: ` SoftReference ` and ` Reference ` . The main difference is that
62+ ` SoftReference ` call it notifier before referent object will be destructed which allows to prevent object be destroyed,
63+ while ` Reference ` call it notifier after referent object was destructed.
4564
65+ Note: What this extension provides aren't quite actual soft and weak references, but it comes close for most use cases.
4666
4767### Notifiers
4868
@@ -53,14 +73,14 @@ will return `null` (unless rare case when object refcount get incremented in des
5373somewhere else).
5474
5575If object destructor or one or more notifiers throw exception, all further notifier callbacks will be called as if
56- that exception was thrown inside ` try-catch ` block. In case one or more exception was thrown, ` Weak\NotifierException `
76+ that exception was thrown inside ` try-catch ` block. In case one or more exceptions were thrown, ` Weak\NotifierException `
5777will be thrown and all thrown exceptions will be available via ` Weak\NotifierException::getExceptions() ` method.
5878
5979
6080### Cloning
6181
62- When ` Weak\Reference ` cloned, notifier cloned too, so when tracking object destroyed, both notifier will be called, but
63- they will be invoked with different ` Weak\Reference ` objects.
82+ When reference is cloned, notifier is cloned too, so when tracked object destroyed, both notifier will be called,
83+ but they will be invoked with different reference objects.
6484
6585``` php
6686<?php
@@ -101,14 +121,14 @@ $obj = null; // outputs "Own notifier called" and then "Object destroyed"
101121
102122### Serializing
103123
104- Serializing ` Weak\Reference ` is prohibited. Attempting to implement the ` Serializable ` interface will lead to a
124+ Serializing reference object is prohibited. Attempting to implement the ` Serializable ` interface will lead to a
105125fatal error.
106126
107127
108128## Stub files
109129
110- If you are also using Composer, it is recommended that you add the [ php-weak-stub] ( https://github.com/pinepain/php-weak-stubs )
111- package as a dev-mode requirement. This provides skeleton definitions and annotations to enable support for auto-completion
130+ If you are also using Composer, it is recommended to add the [ php-weak-stub] ( https://github.com/pinepain/php-weak-stubs )
131+ package as a dev-mode requirement. It provides skeleton definitions and annotations to enable support for auto-completion
112132in your IDE and other code-analysis tools.
113133
114134 composer require --dev pinepain/php-weak-stubs
@@ -137,7 +157,7 @@ To install extension globally run
137157
138158 # sudo make install
139159
140- You will need to copy the extension config to your php dir, here is example for Ubuntu with PHP 7 from
160+ You will need to copy the extension config to your php dir, here is example for Ubuntu with PHP 7.0 from
141161[ Ondřej Surý's PPA for PHP] ( https://launchpad.net/~ondrej/+archive/ubuntu/php ) :
142162
143163 # sudo cp provision/php/weak.ini /etc/php/mods-available/
@@ -156,23 +176,17 @@ You may also want to add php-weak extension as a [composer.json dependency](http
156176## Internals
157177
158178` Weak\Reference ` class is implemented by storing tracked object handlers and then wrapping it original ` dtor_obj ` handler
159- with custom one, which meta-code is:
179+ with a custom one, which meta-code is:
160180
161181``` php
162182$exceptions = [];
163183
164- try {
165- run_original_dtor_obj($object);
166- } catch(Throwable $e) {
167- $exceptions[] = $e;
168- }
169-
170- foreach($weak_references as $weak_ref_object_handle => $weak_reference) {
184+ foreach($soft_references as $soft_ref_object_handle => $soft_reference) {
171185 if (is_array($weak_reference->notifier)) {
172- $weak_reference ->notifier[] = $weak_reference;
173- } elseif (is_callable($weak_reference ->notifier)) {
186+ $soft_reference ->notifier[] = $weak_reference;
187+ } elseif (is_callable($soft_reference ->notifier)) {
174188 try {
175- $weak_reference ->notifier($weak_reference);
189+ $soft_reference ->notifier($weak_reference);
176190 } catch(Throwable $e) {
177191 $exceptions[] = $e;
178192 }
@@ -182,11 +196,38 @@ foreach($weak_references as $weak_ref_object_handle => $weak_reference) {
182196if ($exceptions) {
183197 throw new Weak\NotifierException('One or more exceptions thrown during notifiers calling', $exceptions);
184198}
199+
200+ if (refcount($object) == 1) {
201+ try {
202+ run_original_dtor_obj($object);
203+ } catch(Throwable $e) {
204+ $exceptions[] = $e;
205+ }
206+
207+ foreach($weak_references as $weak_ref_object_handle => $weak_reference) {
208+ if (is_array($weak_reference->notifier)) {
209+ $weak_reference->notifier[] = $weak_reference;
210+ } elseif (is_callable($weak_reference->notifier)) {
211+ try {
212+ $weak_reference->notifier($weak_reference);
213+ } catch(Throwable $e) {
214+ $exceptions[] = $e;
215+ }
216+ }
217+ }
218+
219+ if ($exceptions) {
220+ throw new Weak\NotifierException('One or more exceptions thrown during notifiers calling', $exceptions);
221+ }
222+ } else {
223+ // required while internally PHP GC mark object as it dtor was called before calling dtor
224+ mark_object_as_no_destructor_was_called($object);
225+ }
185226```
186227
187228## Development and testing
188229
189- This extension shipped with Vagrant file which provides basic environment for development and testing purposes.
230+ This extension shipped with Vagrant file which provides basic environment for development and testing purposes.
190231To start it, just type ` vagrant up ` and then ` vagrant ssh ` in php-weak directory.
191232
192233Services available out of the box are:
@@ -204,12 +245,14 @@ between large variety of PHP versions.
204245
205246## Reference:
206247
248+ [ Soft reference on Wikipedia] ( https://en.wikipedia.org/wiki/Soft_reference )
207249 [ Weak reference on Wikipedia] ( https://en.wikipedia.org/wiki/Weak_reference )
208250
209251#### In other languages:
210252
211253##### Java:
212254
255+ - [ Class ` SoftReference<T> ` ] ( https://docs.oracle.com/javase/7/docs/api/java/lang/ref/SoftReference.html )
213256 - [ Class ` WeakReference<T> ` ] ( https://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html )
214257 - [ Guidelines for using the Java 2 reference classes] ( http://www.ibm.com/developerworks/library/j-refs/ )
215258 - [ Strong, Soft, Weak and Phantom References] ( http://neverfear.org/blog/view/150/Strong_Soft_Weak_and_Phantom_References_Java )
0 commit comments