From af3af43ece3121029f2225ab1355081870050048 Mon Sep 17 00:00:00 2001 From: Bogdan Padalko Date: Fri, 1 Jul 2016 19:59:48 +0300 Subject: [PATCH 1/6] Invoke all notifiers even if one of previous or dtor throw an exception --- config.m4 | 9 +- config.w32 | 2 +- php_weak_notifier_exception.c | 131 ++++++++++++++++++ php_weak_notifier_exception.h | 41 ++++++ php_weak_reference.c | 38 ++++- stubs/weak/NotifierException.php | 23 +++ tests/.testsuite.php | 15 ++ tests/002-notifier-exception-basic.phpt | 37 +++++ .../002-reference-exception_in_callback.phpt | 12 +- ...rence-exception_in_multiple_callbacks.phpt | 28 ++-- .../002-reference-exception_in_orig_dtor.phpt | 16 +-- ...e-exception_in_orig_dtor_and_callback.phpt | 19 +-- ...tifier_not_called_after_wr_dies_first.phpt | 8 +- weak.c | 2 + 14 files changed, 335 insertions(+), 46 deletions(-) create mode 100644 php_weak_notifier_exception.c create mode 100644 php_weak_notifier_exception.h create mode 100644 stubs/weak/NotifierException.php create mode 100644 tests/002-notifier-exception-basic.phpt diff --git a/config.m4 b/config.m4 index 93cc9c2..8b77cda 100644 --- a/config.m4 +++ b/config.m4 @@ -27,9 +27,10 @@ if test "$PHP_WEAK" != "no"; then fi fi - PHP_NEW_EXTENSION(weak, [ \ - weak.c \ - php_weak_reference.c \ - php_weak_functions.c \ + PHP_NEW_EXTENSION(weak, [ \ + weak.c \ + php_weak_notifier_exception.c \ + php_weak_reference.c \ + php_weak_functions.c \ ], $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) fi diff --git a/config.w32 b/config.w32 index 563b40c..c09ddcb 100644 --- a/config.w32 +++ b/config.w32 @@ -4,5 +4,5 @@ ARG_ENABLE("weak", "enable weak support", "no"); if (PHP_WEAK != "no") { - EXTENSION("weak", "weak.c php_weak_reference.c php_weak_functions.c", PHP_WEAK_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); + EXTENSION("weak", "weak.c php_weak_notifier_exception.c php_weak_reference.c php_weak_functions.c", PHP_WEAK_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); } diff --git a/php_weak_notifier_exception.c b/php_weak_notifier_exception.c new file mode 100644 index 0000000..f91b288 --- /dev/null +++ b/php_weak_notifier_exception.c @@ -0,0 +1,131 @@ +/* + +----------------------------------------------------------------------+ + | This file is part of the pinepain/php-weak PHP extension. | + | | + | Copyright (c) 2016 Bogdan Padalko | + | | + | Licensed under the MIT license: http://opensource.org/licenses/MIT | + | | + | For the full copyright and license information, please view the | + | LICENSE file that was distributed with this source or visit | + | http://opensource.org/licenses/MIT | + +----------------------------------------------------------------------+ +*/ + +#include "php_weak_notifier_exception.h" +#include "php_weak.h" +#include "zend_exceptions.h" + + +zend_class_entry *php_weak_notifier_exception_class_entry; +#define this_ce php_weak_notifier_exception_class_entry + + +static zend_object *php_weak_notifier_exception_ctor(zend_class_entry *ce) /* {{{ */ +{ + zval obj, thrown; + zend_object *object; + + Z_OBJ(obj) = object = ce->parent->create_object(ce); + + array_init_size(&thrown, 0); + zend_update_property(php_weak_notifier_exception_class_entry, &obj, ZEND_STRL("exceptions"), &thrown); + + return object; +} /* }}} */ + + +void php_weak_create_notifier_exception(zval *exception, const char *message, zval *thrown) /* {{{ */ +{ + object_init_ex(exception, this_ce); + zend_update_property_string(zend_ce_exception, exception, ZEND_STRL("message"), message); + zend_update_property(php_weak_notifier_exception_class_entry, exception, ZEND_STRL("exceptions"), thrown); +} /* }}} */ + +static PHP_METHOD(NotifierException, __construct) /* {{{ */ +{ + zend_string *message = NULL; + zend_long code = 0; + + zval tmp; + zval *exceptions = NULL; + zval *previous = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SalO!", &message, &exceptions, &code, &previous, zend_ce_throwable) == FAILURE) { + return; + } + + if (message) { + zend_update_property_str(zend_ce_exception, getThis(), ZEND_STRL("message"), message); + } + + if (exceptions) { + zend_update_property(this_ce, getThis(), ZEND_STRL("exceptions"), exceptions); + } else { + array_init_size(&tmp, 0); + zend_update_property(this_ce, getThis(), ZEND_STRL("exceptions"), &tmp); + } + + if (code) { + zend_update_property_long(zend_ce_exception, getThis(), ZEND_STRL("code"), code); + } + + if (previous) { + zend_update_property(zend_ce_exception, getThis(), ZEND_STRL("previous"), previous); + } +} + +static PHP_METHOD(NotifierException, getExceptions) /* {{{ */ +{ + zval rv; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETVAL_ZVAL(zend_read_property(php_weak_notifier_exception_class_entry, getThis(), ZEND_STRL("exceptions"), 0, &rv), 1, 0); +} /* }}} */ + + +ZEND_BEGIN_ARG_INFO_EX(arginfo_notifier_exception___construct, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0) + ZEND_ARG_INFO(0, message) + ZEND_ARG_INFO(0, exceptions) + ZEND_ARG_INFO(0, code) + ZEND_ARG_INFO(0, previous) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_notifier_exception_getExceptions, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO() + + +static const zend_function_entry php_weak_notifier_exception_methods[] = { /* {{{ */ + PHP_ME(NotifierException, __construct, arginfo_notifier_exception___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(NotifierException, getExceptions, arginfo_notifier_exception_getExceptions, ZEND_ACC_PUBLIC) + + PHP_FE_END +}; /* }}} */ + + +PHP_MINIT_FUNCTION (php_weak_notifier_exception) /* {{{ */ +{ + zend_class_entry ce; + + INIT_NS_CLASS_ENTRY(ce, PHP_WEAK_NS, "NotifierException", php_weak_notifier_exception_methods); + this_ce = zend_register_internal_class_ex(&ce, zend_ce_exception); + /*this_ce->create_object = php_weak_notifier_exception_ctor;*/ + + zend_declare_property_null(this_ce, ZEND_STRL("exceptions"), ZEND_ACC_PRIVATE); + + + return SUCCESS; +} /* }}} */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_weak_notifier_exception.h b/php_weak_notifier_exception.h new file mode 100644 index 0000000..2d1b675 --- /dev/null +++ b/php_weak_notifier_exception.h @@ -0,0 +1,41 @@ +/* + +----------------------------------------------------------------------+ + | This file is part of the pinepain/php-weak PHP extension. | + | | + | Copyright (c) 2016 Bogdan Padalko | + | | + | Licensed under the MIT license: http://opensource.org/licenses/MIT | + | | + | For the full copyright and license information, please view the | + | LICENSE file that was distributed with this source or visit | + | http://opensource.org/licenses/MIT | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_WEAK_NOTIFIER_EXCEPTION_H +#define PHP_WEAK_NOTIFIER_EXCEPTION_H + +#include "php.h" + +#ifdef ZTS +#include "TSRM.h" +#endif + +extern zend_class_entry *php_weak_notifier_exception_class_entry; + +void php_weak_create_notifier_exception(zval *exception, const char *message, zval *thrown); + +PHP_MINIT_FUNCTION(php_weak_notifier_exception); + + +#endif /* PHP_WEAK_NOTIFIER_EXCEPTION_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/php_weak_reference.c b/php_weak_reference.c index ba16177..27261cf 100644 --- a/php_weak_reference.c +++ b/php_weak_reference.c @@ -13,6 +13,7 @@ */ #include "php_weak_reference.h" +#include "php_weak_notifier_exception.h" #include "php_weak.h" #include "zend_exceptions.h" #include "zend_interfaces.h" @@ -32,6 +33,7 @@ static zend_object_get_debug_info_t spl_object_storage_get_debug_info_orig_handl php_weak_reference_t *php_weak_reference_init(zval *this_ptr, zval *referent_zv, zval *notifier_zv); +static inline void php_weak_store_exceptions(zval *exceptions, zval *tmp); static int php_weak_reference_check_notifier(zval *notifier, zval *this); @@ -197,10 +199,16 @@ void php_weak_reference_call_notifier(zval *reference, zval *notifier) /* {{{ */ } /* }}} */ + void php_weak_referent_object_dtor_obj(zend_object *object) /* {{{ */ { php_weak_referent_t *referent = php_weak_referent_find_ptr(object->handle); + zval exceptions; + zval tmp; + + ZVAL_UNDEF(&exceptions); + assert(NULL != referent); assert(NULL != PHP_WEAK_G(referents)); @@ -209,6 +217,10 @@ void php_weak_referent_object_dtor_obj(zend_object *object) /* {{{ */ referent->original_handlers->dtor_obj(object); + if (EG(exception)) { + php_weak_store_exceptions(&exceptions, &tmp); + } + ZEND_HASH_REVERSE_FOREACH_PTR(&referent->weak_references, reference) { handle = _p->h; reference->referent = NULL; @@ -221,11 +233,12 @@ void php_weak_referent_object_dtor_obj(zend_object *object) /* {{{ */ break; case PHP_WEAK_NOTIFIER_CALLBACK: /* callback notifier */ - if (!EG(exception)) { - php_weak_reference_call_notifier(&reference->this_ptr, &reference->notifier); + php_weak_reference_call_notifier(&reference->this_ptr, &reference->notifier); + + if (EG(exception)) { + php_weak_store_exceptions(&exceptions, &tmp); } break; - default: break; } @@ -234,6 +247,13 @@ void php_weak_referent_object_dtor_obj(zend_object *object) /* {{{ */ } ZEND_HASH_FOREACH_END(); zend_hash_index_del(PHP_WEAK_G(referents), referent->handle); + + if (!Z_ISUNDEF(exceptions)) { + zval exception; + php_weak_create_notifier_exception(&exception, "One or more exceptions thrown during notifiers calling", &exceptions); + + zend_throw_exception_object(&exception); + } } /* }}} */ void php_weak_globals_referents_ht_dtor(zval *zv) /* {{{ */ @@ -340,6 +360,18 @@ php_weak_reference_t *php_weak_reference_init(zval *this_ptr, zval *referent_zv, return reference; } /* }}} */ +static inline void php_weak_store_exceptions(zval *exceptions, zval *tmp) +{ + if (Z_ISUNDEF_P(exceptions)) { + array_init(exceptions); + } + + ZVAL_OBJ(tmp, EG(exception)); + Z_ADDREF_P(tmp); + add_next_index_zval(exceptions, tmp); + + zend_clear_exception(); +} static int php_weak_reference_check_notifier(zval *notifier, zval *this) /* {{{ */ { diff --git a/stubs/weak/NotifierException.php b/stubs/weak/NotifierException.php new file mode 100644 index 0000000..8afedce --- /dev/null +++ b/stubs/weak/NotifierException.php @@ -0,0 +1,23 @@ +exceptions; + } +} diff --git a/tests/.testsuite.php b/tests/.testsuite.php index ebae93b..7d9fef9 100644 --- a/tests/.testsuite.php +++ b/tests/.testsuite.php @@ -32,6 +32,21 @@ public function exception_export(\Throwable $e) echo get_class($e), ': ', $e->getMessage(), PHP_EOL; } + public function weak_exception_export(\Weak\NotifierException $e) + { + $this->exception_export($e); + + if ($e->getPrevious()) { + echo 'previous: '; + $this->exception_export($e->getPrevious()); + } + + foreach ($e->getExceptions() as $thrown) { + echo ' '; + $this->exception_export($thrown); + } + } + public function export($value) { echo gettype($value), ': ', var_export($value, true), PHP_EOL; diff --git a/tests/002-notifier-exception-basic.phpt b/tests/002-notifier-exception-basic.phpt new file mode 100644 index 0000000..518b05d --- /dev/null +++ b/tests/002-notifier-exception-basic.phpt @@ -0,0 +1,37 @@ +--TEST-- +Weak\NotifierException - basic +--SKIPIF-- + +--FILE-- + +EOF +--EXPECTF-- +object(Weak\NotifierException)#1 (8) { + ["message":protected]=> + string(4) "Test" + ["string":"Exception":private]=> + string(0) "" + ["code":protected]=> + int(0) + ["file":protected]=> + string(%d) "%s" + ["line":protected]=> + int(5) + ["trace":"Exception":private]=> + array(0) { + } + ["previous":"Exception":private]=> + NULL + ["exceptions":"Weak\NotifierException":private]=> + array(0) { + } +} +EOF diff --git a/tests/002-reference-exception_in_callback.phpt b/tests/002-reference-exception_in_callback.phpt index 617dd2f..46d7fb6 100644 --- a/tests/002-reference-exception_in_callback.phpt +++ b/tests/002-reference-exception_in_callback.phpt @@ -21,18 +21,14 @@ $wr = new Weak\Reference($obj, $callback); try { $obj = null; -} catch(\Exception $e) { - $helper->exception_export($e); - - if ($e->getPrevious()) { - echo 'previous:'; - $helper->exception_export($e->getPrevious()); - } +} catch(\Weak\NotifierException $e) { + $helper->weak_exception_export($e); } ?> EOF --EXPECT-- WeakTests\TrackingDtor's destructor called -Exception: Test exception from callback +Weak\NotifierException: One or more exceptions thrown during notifiers calling + Exception: Test exception from callback EOF diff --git a/tests/002-reference-exception_in_multiple_callbacks.phpt b/tests/002-reference-exception_in_multiple_callbacks.phpt index e3a2cb9..19ff583 100644 --- a/tests/002-reference-exception_in_multiple_callbacks.phpt +++ b/tests/002-reference-exception_in_multiple_callbacks.phpt @@ -5,6 +5,7 @@ Weak\Reference - exception thrown in callback --FILE-- exception_export($e); - - if ($e->getPrevious()) { - echo 'previous:'; - $helper->exception_export($e->getPrevious()); - } +} catch(\Weak\NotifierException $e) { + $helper->weak_exception_export($e); } + $helper->line(); ?> EOF --EXPECT-- WeakTests\TrackingDtor's destructor called Callback #0 called -Exception: Test exception from callback #1 +Callback #1 called +Callback #2 called +Callback #3 called +Callback #4 called +Callback #5 called +Weak\NotifierException: One or more exceptions thrown during notifiers calling + Exception: Test exception from callback #1 + Exception: Test exception from callback #3 EOF diff --git a/tests/002-reference-exception_in_orig_dtor.phpt b/tests/002-reference-exception_in_orig_dtor.phpt index d924c35..093305b 100644 --- a/tests/002-reference-exception_in_orig_dtor.phpt +++ b/tests/002-reference-exception_in_orig_dtor.phpt @@ -11,6 +11,8 @@ $helper = require '.testsuite.php'; class BadDtor { function __destruct() { + echo 'Dtor called', PHP_EOL; + throw new Exception('Test exception from dtor'); } } @@ -26,17 +28,15 @@ $wr = new Weak\Reference($obj, $callback); try { $obj = null; -} catch(\Exception $e) { - $helper->exception_export($e); - - if ($e->getPrevious()) { - echo 'previous:'; - $helper->exception_export($e->getPrevious()); - } +} catch(\Weak\NotifierException $e) { + $helper->weak_exception_export($e); } ?> EOF --EXPECT-- -Exception: Test exception from dtor +Dtor called +Weak callback called +Weak\NotifierException: One or more exceptions thrown during notifiers calling + Exception: Test exception from dtor EOF diff --git a/tests/002-reference-exception_in_orig_dtor_and_callback.phpt b/tests/002-reference-exception_in_orig_dtor_and_callback.phpt index bf64bc5..639e175 100644 --- a/tests/002-reference-exception_in_orig_dtor_and_callback.phpt +++ b/tests/002-reference-exception_in_orig_dtor_and_callback.phpt @@ -11,6 +11,8 @@ $helper = require '.testsuite.php'; class BadDtor { function __destruct() { + echo 'Dtor called', PHP_EOL; + throw new Exception('Test exception from dtor'); } } @@ -18,6 +20,8 @@ class BadDtor { $obj = new BadDtor(); $callback = function (Weak\Reference $reference) { + echo 'Callback called', PHP_EOL; + throw new \Exception('Test exception from callback'); }; @@ -27,17 +31,16 @@ $wr = new Weak\Reference($obj, $callback); try { $obj = null; -} catch(\Exception $e) { - $helper->exception_export($e); - - if ($e->getPrevious()) { - echo 'previous:'; - $helper->exception_export($e->getPrevious()); - } +} catch(\Weak\NotifierException $e) { + $helper->weak_exception_export($e); } ?> EOF --EXPECT-- -Exception: Test exception from dtor +Dtor called +Callback called +Weak\NotifierException: One or more exceptions thrown during notifiers calling + Exception: Test exception from dtor + Exception: Test exception from callback EOF diff --git a/tests/002-reference-notifier_not_called_after_wr_dies_first.phpt b/tests/002-reference-notifier_not_called_after_wr_dies_first.phpt index 9023924..13f4f58 100644 --- a/tests/002-reference-notifier_not_called_after_wr_dies_first.phpt +++ b/tests/002-reference-notifier_not_called_after_wr_dies_first.phpt @@ -25,8 +25,8 @@ $wr = new Weak\Reference($obj, $callback); try { $obj = null; -} catch(Exception $e) { - $helper->exception_export($e); +} catch(\Weak\NotifierException $e) { + $helper->weak_exception_export($e); $helper->line(); } @@ -37,7 +37,9 @@ $helper->line(); ?> EOF --EXPECT-- -Exception: Destructor throws exception +Weak notifier called +Weak\NotifierException: One or more exceptions thrown during notifiers calling + Exception: Destructor throws exception Referent object dead: ok Referent object invalid: ok diff --git a/weak.c b/weak.c index beef3eb..42c74f7 100644 --- a/weak.c +++ b/weak.c @@ -18,6 +18,7 @@ #include "php_weak_functions.h" #include "php_weak_reference.h" +#include "php_weak_notifier_exception.h" #include "php_weak.h" #include "ext/standard/info.h" @@ -29,6 +30,7 @@ static int le_weak; PHP_MINIT_FUNCTION(weak) /* {{{ */ { + PHP_MINIT(php_weak_notifier_exception)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(php_weak_reference)(INIT_FUNC_ARGS_PASSTHRU); return SUCCESS; From 46a570019644c72aaad57fc22fb30718c580bf53 Mon Sep 17 00:00:00 2001 From: Bogdan Padalko Date: Fri, 1 Jul 2016 20:01:35 +0300 Subject: [PATCH 2/6] Do not call parent dtor if it was not set --- php_weak_reference.c | 8 +++++--- tests/002-reference-exception_in_multiple_callbacks.phpt | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/php_weak_reference.c b/php_weak_reference.c index 27261cf..4ff82c9 100644 --- a/php_weak_reference.c +++ b/php_weak_reference.c @@ -215,10 +215,12 @@ void php_weak_referent_object_dtor_obj(zend_object *object) /* {{{ */ zend_ulong handle; php_weak_reference_t *reference; - referent->original_handlers->dtor_obj(object); + if (referent->original_handlers->dtor_obj) { + referent->original_handlers->dtor_obj(object); - if (EG(exception)) { - php_weak_store_exceptions(&exceptions, &tmp); + if (EG(exception)) { + php_weak_store_exceptions(&exceptions, &tmp); + } } ZEND_HASH_REVERSE_FOREACH_PTR(&referent->weak_references, reference) { diff --git a/tests/002-reference-exception_in_multiple_callbacks.phpt b/tests/002-reference-exception_in_multiple_callbacks.phpt index 19ff583..769228b 100644 --- a/tests/002-reference-exception_in_multiple_callbacks.phpt +++ b/tests/002-reference-exception_in_multiple_callbacks.phpt @@ -5,7 +5,6 @@ Weak\Reference - exception thrown in callback --FILE-- Date: Fri, 1 Jul 2016 20:02:14 +0300 Subject: [PATCH 3/6] Cleanup weakref MINIT --- php_weak_reference.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php_weak_reference.c b/php_weak_reference.c index 4ff82c9..8ad9ef9 100644 --- a/php_weak_reference.c +++ b/php_weak_reference.c @@ -662,10 +662,10 @@ PHP_MINIT_FUNCTION (php_weak_reference) /* {{{ */ zend_class_entry ce; INIT_NS_CLASS_ENTRY(ce, PHP_WEAK_NS, "Reference", php_weak_reference_methods); - ce.serialize = zend_class_serialize_deny; - ce.unserialize = zend_class_unserialize_deny; this_ce = zend_register_internal_class(&ce); this_ce->create_object = php_weak_reference_ctor; + this_ce->serialize = zend_class_serialize_deny; + this_ce->unserialize = zend_class_unserialize_deny; memcpy(&php_weak_reference_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); From 732d93fbbe364b0aec732ef64af09dbb2247b9f0 Mon Sep 17 00:00:00 2001 From: Bogdan Padalko Date: Fri, 1 Jul 2016 20:16:58 +0300 Subject: [PATCH 4/6] Add note about notifiers calling in case exception thrown [skip ci] --- README.md | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3ef8cf3..72f2261 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ $obj = null; // outputs "Object destroyed" This extension adds `Weak` namespace and all entities are created inside it. -There are no INI setting, constants or exceptions provided by this extension. +There are no INI setting or constants provided by this extension. Brief docs about [`Weak\Reference` class](./stubs/weak/Reference.php) and [functions](./stubs/weak/functions.php) may be seen in [stub files](./stubs/weak). @@ -35,6 +35,7 @@ may be seen in [stub files](./stubs/weak). Short list if what provided by this extension is: - `class Weak\Reference` + - `class Weak\NotifierException extend Exception` - `function Weak\refcounted()` - `function Weak\refcount()` - `function Weak\weakrefcounted()` @@ -51,8 +52,9 @@ Note that notification happens *after* referent object destruction, so at the ti will return `null` (unless rare case when object refcount get incremented in destructor, e.g. by storing destructing value somewhere else). -Callback notifier will not be called if referent object destructor or previous notifier callback throws exception, whether -array notifier get executed even in such cases. +If object destructor or one or more notifiers throw exception, all further notifier callbacks will be called as if +that exception was thrown inside `try-catch` block. In case one or more exception was thrown, `Weak\NotifierException` +will be thrown and all thrown exceptions will be available via `Weak\NotifierException::getExceptions()` method. ### Cloning @@ -157,16 +159,28 @@ You may also want to add php-weak extension as a [composer.json dependency](http with custom one, which meta-code is: ```php -run_original_dtor_obj($object); +$exceptions = []; + +try { + run_original_dtor_obj($object); +} catch(Throwable $e) { + $exceptions[] = $e; +} foreach($weak_references as $weak_ref_object_handle => $weak_reference) { if (is_array($weak_reference->notifier)) { $weak_reference->notifier[] = $weak_reference; - } elseif (is_callable($weak_reference->notifier) && $no_exception_thrown) { - $weak_reference->notifier($weak_reference); + } elseif (is_callable($weak_reference->notifier)) { + try { + $weak_reference->notifier($weak_reference); + } catch(Throwable $e) { + $exceptions[] = $e; + } } - - unset($weak_references[$weak_ref_object_handle]); +} + +if ($exceptions) { + throw new Weak\NotifierException('One or more exceptions thrown during notifiers calling', $exceptions); } ``` From 4c55673724623a7070d04b65a4a2e650c00e9e6f Mon Sep 17 00:00:00 2001 From: Bogdan Padalko Date: Fri, 1 Jul 2016 22:07:52 +0300 Subject: [PATCH 5/6] Fix object_handle() phpdoc [skip ci] --- stubs/weak/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/weak/functions.php b/stubs/weak/functions.php index 65be179..a813af1 100644 --- a/stubs/weak/functions.php +++ b/stubs/weak/functions.php @@ -60,7 +60,7 @@ function weakrefcount(object $value) : int {} function weakrefs(object $value) : array {} /** - * Get object's weak references + * Get object's handle id * * @param object $value * From 913e537b9186a24e1c410fa6cdfb64b79f330b8b Mon Sep 17 00:00:00 2001 From: Bogdan Padalko Date: Fri, 1 Jul 2016 20:49:23 +0300 Subject: [PATCH 6/6] Fix tests against PHP 7.1 `debug_zval_dump()` function behavior is different in PHP 7.0 and PHP 7.1, see https://3v4l.org/CiV5Q, so we switch to `var_dump()` in some places --- tests/002-reference-clone_extended.phpt | 44 ++-- tests/002-reference-dump_extended.phpt | 26 +-- tests/002-reference-notifier_array.phpt | 50 ++--- tests/002-reference-notifier_array_clone.phpt | 192 +++--------------- ...-reference-notifier_array_reliability.phpt | 192 +++--------------- 5 files changed, 93 insertions(+), 411 deletions(-) diff --git a/tests/002-reference-clone_extended.phpt b/tests/002-reference-clone_extended.phpt index 4510703..ecbb108 100644 --- a/tests/002-reference-clone_extended.phpt +++ b/tests/002-reference-clone_extended.phpt @@ -20,71 +20,59 @@ $helper = require '.testsuite.php'; $obj = new \stdClass(); -$notifier = function (Weak\Reference $ref) use ($helper) { +$notifier = function (Weak\Reference $ref) { echo 'Notified: '; - $helper->dump($ref); + var_dump($ref); }; $wr = new ExtendedReference($obj, $notifier, [42]); -$helper->dump($wr); +var_dump($wr); $helper->line(); $wr2 = clone $wr; -$helper->dump($wr2); +var_dump($wr2); $helper->line(); ?> EOF --EXPECT-- -object(WeakTests\ExtendedReference)#4 (3) refcount(3){ +object(WeakTests\ExtendedReference)#4 (3) { ["test":"WeakTests\ExtendedReference":private]=> - array(1) refcount(2){ + array(1) { [0]=> int(42) } ["referent":"Weak\Reference":private]=> - object(stdClass)#2 (0) refcount(2){ + object(stdClass)#2 (0) { } ["notifier":"Weak\Reference":private]=> - object(Closure)#3 (2) refcount(3){ - ["static"]=> - array(1) refcount(1){ - ["helper"]=> - object(Testsuite)#1 (0) refcount(4){ - } - } + object(Closure)#3 (1) { ["parameter"]=> - array(1) refcount(1){ + array(1) { ["$ref"]=> - string(10) "" refcount(1) + string(10) "" } } } -object(WeakTests\ExtendedReference)#5 (3) refcount(3){ +object(WeakTests\ExtendedReference)#5 (3) { ["test":"WeakTests\ExtendedReference":private]=> - array(1) refcount(3){ + array(1) { [0]=> int(42) } ["referent":"Weak\Reference":private]=> - object(stdClass)#2 (0) refcount(2){ + object(stdClass)#2 (0) { } ["notifier":"Weak\Reference":private]=> - object(Closure)#3 (2) refcount(4){ - ["static"]=> - array(1) refcount(1){ - ["helper"]=> - object(Testsuite)#1 (0) refcount(4){ - } - } + object(Closure)#3 (1) { ["parameter"]=> - array(1) refcount(1){ + array(1) { ["$ref"]=> - string(10) "" refcount(1) + string(10) "" } } } diff --git a/tests/002-reference-dump_extended.phpt b/tests/002-reference-dump_extended.phpt index b7a90e4..a79bacb 100644 --- a/tests/002-reference-dump_extended.phpt +++ b/tests/002-reference-dump_extended.phpt @@ -16,49 +16,49 @@ $obj = new stdClass(); $wr = new ExtendedReference($obj, function (Weak\Reference $reference) {}, [42]); -$helper->dump($wr); +var_dump($wr); $helper->line(); $obj = null; -$helper->dump($wr); +var_dump($wr); $helper->line(); ?> EOF --EXPECT-- -object(WeakTests\ExtendedReference)#3 (3) refcount(3){ +object(WeakTests\ExtendedReference)#3 (3) { ["test":"WeakTests\ExtendedReference":private]=> - array(1) refcount(2){ + array(1) { [0]=> int(42) } ["referent":"Weak\Reference":private]=> - object(stdClass)#2 (0) refcount(2){ + object(stdClass)#2 (0) { } ["notifier":"Weak\Reference":private]=> - object(Closure)#4 (1) refcount(2){ + object(Closure)#4 (1) { ["parameter"]=> - array(1) refcount(1){ + array(1) { ["$reference"]=> - string(10) "" refcount(1) + string(10) "" } } } -object(WeakTests\ExtendedReference)#3 (3) refcount(3){ +object(WeakTests\ExtendedReference)#3 (3) { ["test":"WeakTests\ExtendedReference":private]=> - array(1) refcount(2){ + array(1) { [0]=> int(42) } ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - object(Closure)#4 (1) refcount(2){ + object(Closure)#4 (1) { ["parameter"]=> - array(1) refcount(1){ + array(1) { ["$reference"]=> - string(10) "" refcount(1) + string(10) "" } } } diff --git a/tests/002-reference-notifier_array.phpt b/tests/002-reference-notifier_array.phpt index d691b94..d8bbde1 100644 --- a/tests/002-reference-notifier_array.phpt +++ b/tests/002-reference-notifier_array.phpt @@ -14,69 +14,43 @@ $notifier = []; $wr = new Weak\Reference($obj, $notifier); -$helper->dump($notifier); +var_dump($notifier); $obj = null; -$helper->dump($notifier); +var_dump($notifier); $wr = null; -$helper->dump($notifier); +var_dump($notifier); $helper->line(); ?> EOF --EXPECT-- -array(0) refcount(4){ +array(0) { } -array(1) refcount(4){ +array(1) { [0]=> - object(Weak\Reference)#3 (2) refcount(2){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(1) refcount(5){ + array(1) { [0]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(1) refcount(6){ - [0]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* } } } -array(1) refcount(4){ +array(1) { [0]=> - object(Weak\Reference)#3 (2) refcount(1){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(1) refcount(5){ + array(1) { [0]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(1) refcount(6){ - [0]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* } } } diff --git a/tests/002-reference-notifier_array_clone.phpt b/tests/002-reference-notifier_array_clone.phpt index 6359f77..8749c2e 100644 --- a/tests/002-reference-notifier_array_clone.phpt +++ b/tests/002-reference-notifier_array_clone.phpt @@ -15,231 +15,91 @@ $wr = new Weak\Reference($obj, $notifier); $wr2 = clone $wr; -$helper->dump($notifier); +var_dump($notifier); $obj = null; -$helper->dump($notifier); +var_dump($notifier); $wr = null; -$helper->dump($notifier); +var_dump($notifier); $helper->line(); ?> EOF --EXPECT-- -array(0) refcount(5){ +array(0) { } -array(2) refcount(5){ +array(2) { [0]=> - object(Weak\Reference)#4 (2) refcount(2){ + object(Weak\Reference)#4 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(6){ + array(2) { [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* [1]=> - object(Weak\Reference)#3 (2) refcount(2){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } + *RECURSION* } } } [1]=> - object(Weak\Reference)#3 (2) refcount(2){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(6){ + array(2) { [0]=> - object(Weak\Reference)#4 (2) refcount(2){ + object(Weak\Reference)#4 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } + *RECURSION* } [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* } } } -array(2) refcount(5){ +array(2) { [0]=> - object(Weak\Reference)#4 (2) refcount(2){ + object(Weak\Reference)#4 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(6){ + array(2) { [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* [1]=> - object(Weak\Reference)#3 (2) refcount(1){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } + *RECURSION* } } } [1]=> - object(Weak\Reference)#3 (2) refcount(1){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(6){ + array(2) { [0]=> - object(Weak\Reference)#4 (2) refcount(2){ + object(Weak\Reference)#4 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } + *RECURSION* } [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#4 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* } } } diff --git a/tests/002-reference-notifier_array_reliability.phpt b/tests/002-reference-notifier_array_reliability.phpt index 292df29..727031e 100644 --- a/tests/002-reference-notifier_array_reliability.phpt +++ b/tests/002-reference-notifier_array_reliability.phpt @@ -20,7 +20,7 @@ $wr2 = new Weak\Reference($obj, function () { $wr2 = new Weak\Reference($obj, $notifier); -$helper->dump($notifier); +var_dump($notifier); try { $obj = null; @@ -28,227 +28,87 @@ try { $helper->exception_export($e); } -$helper->dump($notifier); +var_dump($notifier); $wr1 = null; -$helper->dump($notifier); +var_dump($notifier); $helper->line(); ?> EOF --EXPECT-- -array(0) refcount(5){ +array(0) { } -array(2) refcount(5){ +array(2) { [0]=> - object(Weak\Reference)#6 (2) refcount(2){ + object(Weak\Reference)#6 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(6){ + array(2) { [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* [1]=> - object(Weak\Reference)#3 (2) refcount(2){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } + *RECURSION* } } } [1]=> - object(Weak\Reference)#3 (2) refcount(2){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(6){ + array(2) { [0]=> - object(Weak\Reference)#6 (2) refcount(2){ + object(Weak\Reference)#6 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } + *RECURSION* } [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* } } } -array(2) refcount(5){ +array(2) { [0]=> - object(Weak\Reference)#6 (2) refcount(2){ + object(Weak\Reference)#6 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(6){ + array(2) { [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* [1]=> - object(Weak\Reference)#3 (2) refcount(1){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } + *RECURSION* } } } [1]=> - object(Weak\Reference)#3 (2) refcount(1){ + object(Weak\Reference)#3 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(6){ + array(2) { [0]=> - object(Weak\Reference)#6 (2) refcount(2){ + object(Weak\Reference)#6 (2) { ["referent":"Weak\Reference":private]=> NULL ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } + *RECURSION* } [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - array(2) refcount(7){ - [0]=> - object(Weak\Reference)#6 (2) refcount(2){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - [1]=> - object(Weak\Reference)#3 (2) refcount(1){ - ["referent":"Weak\Reference":private]=> - NULL - ["notifier":"Weak\Reference":private]=> - *RECURSION* - } - } - } + *RECURSION* } } }