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,13 +36,15 @@ 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() `
4150 - ` function Weak\softrefcounted() `
@@ -47,6 +56,13 @@ Short list if what provided by this extension is:
4756 - ` function Weak\object_handle() `
4857 - ` function Weak\is_obj_destructor_called() `
4958
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.
64+
65+ Note: What this extension provides aren't quite actual soft and weak references, but it comes close for most use cases.
5066
5167### Notifiers
5268
@@ -57,14 +73,14 @@ will return `null` (unless rare case when object refcount get incremented in des
5773somewhere else).
5874
5975If object destructor or one or more notifiers throw exception, all further notifier callbacks will be called as if
60- 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 `
6177will be thrown and all thrown exceptions will be available via ` Weak\NotifierException::getExceptions() ` method.
6278
6379
6480### Cloning
6581
66- When ` Weak\Reference ` cloned, notifier cloned too, so when tracking object destroyed, both notifier will be called, but
67- 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.
6884
6985``` php
7086<?php
@@ -105,14 +121,14 @@ $obj = null; // outputs "Own notifier called" and then "Object destroyed"
105121
106122### Serializing
107123
108- 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
109125fatal error.
110126
111127
112128## Stub files
113129
114- If you are also using Composer, it is recommended that you add the [ php-weak-stub] ( https://github.com/pinepain/php-weak-stubs )
115- 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
116132in your IDE and other code-analysis tools.
117133
118134 composer require --dev pinepain/php-weak-stubs
@@ -141,7 +157,7 @@ To install extension globally run
141157
142158 # sudo make install
143159
144- 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
145161[ Ondřej Surý's PPA for PHP] ( https://launchpad.net/~ondrej/+archive/ubuntu/php ) :
146162
147163 # sudo cp provision/php/weak.ini /etc/php/mods-available/
@@ -160,23 +176,17 @@ You may also want to add php-weak extension as a [composer.json dependency](http
160176## Internals
161177
162178` Weak\Reference ` class is implemented by storing tracked object handlers and then wrapping it original ` dtor_obj ` handler
163- with custom one, which meta-code is:
179+ with a custom one, which meta-code is:
164180
165181``` php
166182$exceptions = [];
167183
168- try {
169- run_original_dtor_obj($object);
170- } catch(Throwable $e) {
171- $exceptions[] = $e;
172- }
173-
174- foreach($weak_references as $weak_ref_object_handle => $weak_reference) {
184+ foreach($soft_references as $soft_ref_object_handle => $soft_reference) {
175185 if (is_array($weak_reference->notifier)) {
176- $weak_reference ->notifier[] = $weak_reference;
177- } elseif (is_callable($weak_reference ->notifier)) {
186+ $soft_reference ->notifier[] = $weak_reference;
187+ } elseif (is_callable($soft_reference ->notifier)) {
178188 try {
179- $weak_reference ->notifier($weak_reference);
189+ $soft_reference ->notifier($weak_reference);
180190 } catch(Throwable $e) {
181191 $exceptions[] = $e;
182192 }
@@ -186,11 +196,38 @@ foreach($weak_references as $weak_ref_object_handle => $weak_reference) {
186196if ($exceptions) {
187197 throw new Weak\NotifierException('One or more exceptions thrown during notifiers calling', $exceptions);
188198}
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+ }
189226```
190227
191228## Development and testing
192229
193- 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.
194231To start it, just type ` vagrant up ` and then ` vagrant ssh ` in php-weak directory.
195232
196233Services available out of the box are:
@@ -208,12 +245,14 @@ between large variety of PHP versions.
208245
209246## Reference:
210247
248+ [ Soft reference on Wikipedia] ( https://en.wikipedia.org/wiki/Soft_reference )
211249 [ Weak reference on Wikipedia] ( https://en.wikipedia.org/wiki/Weak_reference )
212250
213251#### In other languages:
214252
215253##### Java:
216254
255+ - [ Class ` SoftReference<T> ` ] ( https://docs.oracle.com/javase/7/docs/api/java/lang/ref/SoftReference.html )
217256 - [ Class ` WeakReference<T> ` ] ( https://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html )
218257 - [ Guidelines for using the Java 2 reference classes] ( http://www.ibm.com/developerworks/library/j-refs/ )
219258 - [ Strong, Soft, Weak and Phantom References] ( http://neverfear.org/blog/view/150/Strong_Soft_Weak_and_Phantom_References_Java )
0 commit comments