Skip to content
This repository was archived by the owner on Jul 7, 2018. It is now read-only.

Commit aaaedca

Browse files
authored
Merge pull request #13 from pinepain/soft_reference
Add SoftReference
2 parents 77e191b + 3c84ead commit aaaedca

File tree

69 files changed

+3268
-200
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+3268
-200
lines changed

.travis.yml

-6
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ env:
2222
before_install:
2323
- phpize && ./configure && make
2424

25-
install:
26-
2725
script:
2826
- sh -c "make test | tee result.txt"
2927
- sh test-report.sh
@@ -32,7 +30,3 @@ addons:
3230
apt:
3331
packages:
3432
- valgrind
35-
36-
#notifications:
37-
# email:
38-

README.md

+70-27
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
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

1617
use 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

3037
There 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)
3340
may be seen in [stub files](./stubs/weak).
3441

3542
Short 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
5373
somewhere else).
5474

5575
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`
5777
will 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
105125
fatal 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
112132
in 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) {
182196
if ($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.
190231
To start it, just type `vagrant up` and then `vagrant ssh` in php-weak directory.
191232

192233
Services 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)

php_weak_functions.c

+107-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,77 @@ PHP_FUNCTION(refcount)
4141
RETURN_LONG(0);
4242
} /* }}} */
4343

44+
PHP_FUNCTION(softrefcounted) /* {{{ */
45+
{
46+
zval *zv;
47+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zv) == FAILURE) {
48+
return;
49+
}
50+
51+
if (IS_OBJECT == Z_TYPE_P(zv)) {
52+
php_weak_referent_t *referent = php_weak_referent_find_ptr((zend_ulong)Z_OBJ_HANDLE_P(zv));
53+
54+
RETURN_BOOL(NULL != referent && zend_hash_num_elements(&referent->soft_references));
55+
}
56+
57+
RETURN_BOOL(0);
58+
} /* }}} */
59+
60+
PHP_FUNCTION(softrefcount) /* {{{ */
61+
{
62+
zval *zv;
63+
64+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zv) == FAILURE) {
65+
return;
66+
}
67+
68+
if (IS_OBJECT == Z_TYPE_P(zv)) {
69+
70+
php_weak_referent_t *referent = php_weak_referent_find_ptr((zend_ulong)Z_OBJ_HANDLE_P(zv));
71+
72+
if (NULL == referent) {
73+
RETURN_LONG(0);
74+
}
75+
76+
RETURN_LONG(zend_hash_num_elements(&referent->soft_references));
77+
}
78+
79+
RETURN_LONG(0);
80+
} /* }}} */
81+
82+
PHP_FUNCTION(softrefs) /* {{{ */
83+
{
84+
zval *zv;
85+
zval softrefs;
86+
87+
php_weak_reference_t *reference;
88+
89+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zv) == FAILURE) {
90+
return;
91+
}
92+
93+
ZVAL_UNDEF(&softrefs);
94+
95+
if (IS_OBJECT == Z_TYPE_P(zv)) {
96+
php_weak_referent_t *referent = php_weak_referent_find_ptr((zend_ulong)Z_OBJ_HANDLE_P(zv));
97+
98+
if (NULL != referent) {
99+
array_init_size(&softrefs, zend_hash_num_elements(&referent->soft_references));
100+
101+
ZEND_HASH_FOREACH_PTR(&referent->soft_references, reference) {
102+
add_next_index_zval(&softrefs, &reference->this_ptr);
103+
Z_ADDREF(reference->this_ptr);
104+
} ZEND_HASH_FOREACH_END();
105+
}
106+
}
107+
108+
if (IS_UNDEF == Z_TYPE(softrefs)) {
109+
array_init_size(&softrefs, 0);
110+
}
111+
112+
RETURN_ZVAL(&softrefs, 1, 1);
113+
} /* }}} */
114+
44115
PHP_FUNCTION(weakrefcounted) /* {{{ */
45116
{
46117
zval *zv;
@@ -117,12 +188,27 @@ PHP_FUNCTION(object_handle) /* {{{ */
117188
zval *zv;
118189

119190
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zv) == FAILURE) {
120-
RETURN_NULL();
191+
return;
121192
}
122193

123194
RETURN_LONG((uint32_t)Z_OBJ_HANDLE_P(zv));
124195
} /* }}} */
125196

197+
PHP_FUNCTION(is_obj_destructor_called) /* {{{ */
198+
{
199+
zval *zv;
200+
201+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &zv) == FAILURE) {
202+
return;
203+
}
204+
205+
zend_object *obj = Z_OBJ_P(zv);
206+
207+
uint32_t flags = GC_FLAGS(obj);
208+
209+
RETURN_BOOL(flags & IS_OBJ_DESTRUCTOR_CALLED);
210+
} /* }}} */
211+
126212

127213
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(refcounted_arg, ZEND_RETURN_VALUE, 1, _IS_BOOL, NULL, 0)
128214
ZEND_ARG_INFO(0, value)
@@ -132,6 +218,18 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(refcount_arg, ZEND_RETURN_VALUE, 1, IS_L
132218
ZEND_ARG_INFO(0, value)
133219
ZEND_END_ARG_INFO()
134220

221+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(softrefcounted_arg, ZEND_RETURN_VALUE, 1, _IS_BOOL, NULL, 0)
222+
ZEND_ARG_INFO(0, object)
223+
ZEND_END_ARG_INFO()
224+
225+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(softrefcount_arg, ZEND_RETURN_VALUE, 1, IS_LONG, NULL, 0)
226+
ZEND_ARG_INFO(0, object)
227+
ZEND_END_ARG_INFO()
228+
229+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(softrefs_arg, ZEND_RETURN_VALUE, 1, IS_ARRAY, NULL, 0)
230+
ZEND_ARG_INFO(0, object)
231+
ZEND_END_ARG_INFO()
232+
135233
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(weakrefcounted_arg, ZEND_RETURN_VALUE, 1, _IS_BOOL, NULL, 0)
136234
ZEND_ARG_INFO(0, object)
137235
ZEND_END_ARG_INFO()
@@ -148,16 +246,24 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(object_handle_arg, ZEND_RETURN_VALUE, 1,
148246
ZEND_ARG_INFO(0, object)
149247
ZEND_END_ARG_INFO()
150248

249+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(is_obj_destructor_called_arg, ZEND_RETURN_VALUE, 1, _IS_BOOL, NULL, 0)
250+
ZEND_ARG_INFO(0, object)
251+
ZEND_END_ARG_INFO()
151252

152253
const zend_function_entry php_weak_functions[] = { /* {{{ */
153254
ZEND_NS_FE(PHP_WEAK_NS, refcounted, refcounted_arg)
154255
ZEND_NS_FE(PHP_WEAK_NS, refcount, refcount_arg)
155256

257+
ZEND_NS_FE(PHP_WEAK_NS, softrefcounted, softrefcounted_arg)
258+
ZEND_NS_FE(PHP_WEAK_NS, softrefcount, softrefcount_arg)
259+
ZEND_NS_FE(PHP_WEAK_NS, softrefs, softrefs_arg)
260+
156261
ZEND_NS_FE(PHP_WEAK_NS, weakrefcounted, weakrefcounted_arg)
157262
ZEND_NS_FE(PHP_WEAK_NS, weakrefcount, weakrefcount_arg)
158263
ZEND_NS_FE(PHP_WEAK_NS, weakrefs, weakrefs_arg)
159264

160265
ZEND_NS_FE(PHP_WEAK_NS, object_handle, object_handle_arg)
266+
ZEND_NS_FE(PHP_WEAK_NS, is_obj_destructor_called, is_obj_destructor_called_arg)
161267

162268
PHP_FE_END
163269
}; /* }}} */

0 commit comments

Comments
 (0)