4
4
[ ![ Windows Build status] ( https://ci.appveyor.com/api/projects/status/7r07eydi6c3lj36a/branch/master?svg=true )] ( https://ci.appveyor.com/project/pinepain/php-weak )
5
5
[ ![ GitHub license] ( https://img.shields.io/badge/license-MIT-blue.svg )] ( https://raw.githubusercontent.com/pinepain/php-weak/master/LICENSE )
6
6
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.
9
10
10
11
11
12
## Usage
@@ -14,12 +15,18 @@ as a ground for other weak data structures.
14
15
<?php
15
16
16
17
use Weak\Reference;
18
+ use Weak\SoftReference;
17
19
18
- $obj = new stdClass();
20
+ $obj = new class {
21
+ public function __destruct() {
22
+ echo 'Destructor called', PHP_EOL;
23
+ }
24
+ };
19
25
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; });
21
28
22
- $obj = null; // outputs "Object destroyed"
29
+ $obj = null; // outputs "Object will be destroyed", "Destructor called", "Object destroyed" in this specific order.
23
30
```
24
31
25
32
@@ -29,20 +36,33 @@ This extension adds `Weak` namespace and all entities are created inside it.
29
36
30
37
There are no INI setting or constants provided by this extension.
31
38
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 )
33
40
may be seen in [ stub files] ( ./stubs/weak ) .
34
41
35
42
Short list if what provided by this extension is:
36
43
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 )
39
48
- ` function Weak\refcounted() `
40
49
- ` function Weak\refcount() `
50
+ - ` function Weak\softrefcounted() `
51
+ - ` function Weak\softrefcount() `
52
+ - ` function Weak\softrefs() `
41
53
- ` function Weak\weakrefcounted() `
42
54
- ` function Weak\weakrefcount() `
43
55
- ` function Weak\weakrefs() `
44
56
- ` 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.
45
64
65
+ Note: What this extension provides aren't quite actual soft and weak references, but it comes close for most use cases.
46
66
47
67
### Notifiers
48
68
@@ -53,14 +73,14 @@ will return `null` (unless rare case when object refcount get incremented in des
53
73
somewhere else).
54
74
55
75
If 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 `
57
77
will be thrown and all thrown exceptions will be available via ` Weak\NotifierException::getExceptions() ` method.
58
78
59
79
60
80
### Cloning
61
81
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.
64
84
65
85
``` php
66
86
<?php
@@ -101,14 +121,14 @@ $obj = null; // outputs "Own notifier called" and then "Object destroyed"
101
121
102
122
### Serializing
103
123
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
105
125
fatal error.
106
126
107
127
108
128
## Stub files
109
129
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
112
132
in your IDE and other code-analysis tools.
113
133
114
134
composer require --dev pinepain/php-weak-stubs
@@ -137,7 +157,7 @@ To install extension globally run
137
157
138
158
# sudo make install
139
159
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
141
161
[ Ondřej Surý's PPA for PHP] ( https://launchpad.net/~ondrej/+archive/ubuntu/php ) :
142
162
143
163
# 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
156
176
## Internals
157
177
158
178
` 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:
160
180
161
181
``` php
162
182
$exceptions = [];
163
183
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) {
171
185
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)) {
174
188
try {
175
- $weak_reference ->notifier($weak_reference);
189
+ $soft_reference ->notifier($weak_reference);
176
190
} catch(Throwable $e) {
177
191
$exceptions[] = $e;
178
192
}
@@ -182,11 +196,38 @@ foreach($weak_references as $weak_ref_object_handle => $weak_reference) {
182
196
if ($exceptions) {
183
197
throw new Weak\NotifierException('One or more exceptions thrown during notifiers calling', $exceptions);
184
198
}
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
+ }
185
226
```
186
227
187
228
## Development and testing
188
229
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.
190
231
To start it, just type ` vagrant up ` and then ` vagrant ssh ` in php-weak directory.
191
232
192
233
Services available out of the box are:
@@ -204,12 +245,14 @@ between large variety of PHP versions.
204
245
205
246
## Reference:
206
247
248
+ [ Soft reference on Wikipedia] ( https://en.wikipedia.org/wiki/Soft_reference )
207
249
[ Weak reference on Wikipedia] ( https://en.wikipedia.org/wiki/Weak_reference )
208
250
209
251
#### In other languages:
210
252
211
253
##### Java:
212
254
255
+ - [ Class ` SoftReference<T> ` ] ( https://docs.oracle.com/javase/7/docs/api/java/lang/ref/SoftReference.html )
213
256
- [ Class ` WeakReference<T> ` ] ( https://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html )
214
257
- [ Guidelines for using the Java 2 reference classes] ( http://www.ibm.com/developerworks/library/j-refs/ )
215
258
- [ Strong, Soft, Weak and Phantom References] ( http://neverfear.org/blog/view/150/Strong_Soft_Weak_and_Phantom_References_Java )
0 commit comments