├── provision
├── php
│ └── ref.ini
├── apache
│ ├── ports.conf
│ └── 000-default.conf
├── nginx
│ └── default
├── provision.sh
└── .bashrc
├── config.w32
├── test-report.sh
├── scripts
├── subsplit.sh
├── replace_expect.php
└── refresh-package-xml.php
├── tests
├── 001-extension_info.phpt
├── 002-WeakReference-notifier_callable_string.phpt
├── 004-SoftReference-notifier_callable_string.phpt
├── 002-WeakReference-orig_dtor_called_after_wr_dies_first.phpt
├── 004-SoftReference-orig_dtor_called_after_wr_dies_first.phpt
├── 002-WeakReference-orig_dtor_and_notifier_when_wr_dies_first.phpt
├── 004-SoftReference-orig_dtor_and_notifier_when_wr_dies_first.phpt
├── 002-WeakReference-orig_dtor_called_once.phpt
├── 004-SoftReference-orig_dtor_called_once.phpt
├── 001-extension-loaded.phpt
├── 002-WeakReference-notifier_invalid_callback.phpt
├── 004-SoftReference-notifier_invalid_callback.phpt
├── 002-WeakReference-orig_dtor_called.phpt
├── 004-SoftReference-orig_dtor_called.phpt
├── 002-WeakReference-extended_dtor_called.phpt
├── 004-SoftReference-extended_dtor_called.phpt
├── 002-WeakReference-notifier_callable_array.phpt
├── 004-SoftReference-notifier_callable_array.phpt
├── 002-WeakReference-exception-before-notifier.phpt
├── 004-SoftReference-exception-before-notifier.phpt
├── 002-WeakReference-multiple_obj.phpt
├── 004-SoftReference-multiple_obj.phpt
├── 002-NotifierException-basic.phpt
├── 004-SoftReference-notified_with_weak.phpt
├── 002-WeakReference-notifier.phpt
├── 004-SoftReference-notifier.phpt
├── 002-WeakReference-exception_in_callback.phpt
├── 004-SoftReference-exception_in_callback.phpt
├── 002-WeakReference-multiple_with_notify_and_orig_dtor.phpt
├── 002-WeakReference-serialize_extended_not_allowed.phpt
├── 004-SoftReference-multiple_with_notify_and_orig_dtor.phpt
├── 004-SoftReference-serialize_extended_not_allowed.phpt
├── 002-WeakReference-die_in_dtor.phpt
├── 005-Soft-and-Weak-Reference-exception-before-notifier.phpt
├── 002-WeakReference-exception-before-and-from-notifier.phpt
├── 004-SoftReference-exception-before-and-from-notifier.phpt
├── 004-SoftReference-die_in_dtor.phpt
├── 002-WeakReference-exception_in_orig_dtor.phpt
├── 004-SoftReference-exception_in_orig_dtor.phpt
├── 002-WeakReference-orig_dtor_and_notify.phpt
├── 004-SoftReference-orig_dtor_and_notify.phpt
├── 002-WeakReference-notified.phpt
├── 004-SoftReference-notified_prevent_destoying_forever_with_weak.phpt
├── 002-WeakReference-serialize_not_allowed.phpt
├── 004-SoftReference-notified_prevent_destoying_with_weak.phpt
├── 004-SoftReference-serialize_not_allowed.phpt
├── 002-WeakReference-exception_in_orig_dtor_and_callback.phpt
├── 004-SoftReference-exception_in_orig_dtor_and_callback.phpt
├── 002-WeakReference-notifier_clone_change.phpt
├── 004-SoftReference-notifier_clone_change.phpt
├── 002-WeakReference-multiple_weak.phpt
├── 004-SoftReference-multiple_weak.phpt
├── 005-Soft-and-Weak-Reference-exception-before-and-from-notifier.phpt
├── 004-SoftReference-notified.phpt
├── 004-SoftReference-notified_prevent_destoying_multiple.phpt
├── 002-WeakReference-notifier_not_called_after_wr_dies_first.phpt
├── 004-SoftReference-notifier_not_called_after_wr_dies_first.phpt
├── 001-verify-method-case.phpt
├── 002-WeakReference-reference-deleted-during-notifier.phpt
├── 002-WeakReference-basic.phpt
├── 004-SofReference-basic.phpt
├── 002-WeakReference-dump_extended.phpt
├── 004-SoftReference-dump_extended.phpt
├── 002-WeakReference-spl_object_storage_debug_hash_consistent.phpt
├── 004-SoftReference-spl_object_storage_debug_hash_consistent.phpt
├── 002-WeakReference-spl_hash_consistent.phpt
├── 004-SoftReference-spl_hash_consistent.phpt
├── 002-WeakReference-clone_extended.phpt
├── 002-WeakReference-exception_in_multiple_callbacks.phpt
├── 004-SoftReference-exception_in_multiple_callbacks.phpt
├── 004-SoftReference-clone_extended.phpt
├── 002-AbstractReference-basic.phpt
├── 002-WeakReference-object-handle-reuse.phpt
├── 002-WeakReference-closure.phpt
├── 004-SoftReference-closure.phpt
├── 003-functions-weakrefcounted_after_all_refs_died.phpt
├── 002-AbstractReference-clone.phpt
├── 002-WeakReference-notifier_change.phpt
├── 004-SoftReference-notifier_change.phpt
├── 002-WeakReference-spl_object_storage_hash_consistent.phpt
├── 004-SoftReference-spl_object_storage_hash_consistent.phpt
├── .stubs.php
├── 001-verify-methods-signature.phpt
├── 003-functions-soft.phpt
├── 002-WeakReference-clone.phpt
├── 004-SoftReference-clone.phpt
├── 004-SoftReference-notified_prevent_destoying.phpt
├── 004-SoftReference-notified_prevent_destoying_forever.phpt
├── 003-functions-soft-and-weak.phpt
├── 003-functions.phpt
├── .testsuite.php
└── 001-verify_extension_entities.phpt
├── stubs
├── src
│ ├── SoftReference.php
│ ├── WeakReference.php
│ ├── NotifierException.php
│ ├── functions.php
│ └── AbstractReference.php
├── composer.json
├── README.md
└── LICENSE
├── .travis.yml
├── php_ref_functions.h
├── .gitignore
├── CMakeLists.txt
├── php_ref_notifier_exception.h
├── LICENSE
├── php_ref.h
├── Vagrantfile
├── config.m4
├── php_ref_reference.h
├── ref.c
├── php_ref_notifier_exception.c
└── php_ref_functions.c
/provision/php/ref.ini:
--------------------------------------------------------------------------------
1 | ; configuration for php weak module
2 | ; priority=20
3 | extension=weak.so
4 |
--------------------------------------------------------------------------------
/config.w32:
--------------------------------------------------------------------------------
1 | #ARG_ENABLE("ref", "enable ref support", "no");
2 |
3 | if (PHP_REF != "no") {
4 | EXTENSION("ref", "ref.c", PHP_REF_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
5 | }
6 | ``
7 |
--------------------------------------------------------------------------------
/test-report.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | result=`find tests -type f -and -name "*.diff" -or -name "*.out" -or -name "*.mem" | sort | while read file; do
3 | echo "FILE: ${file}"
4 | cat "$file"
5 | echo "\n"
6 | done`
7 |
8 | if [ -n "$result" ]; then
9 | echo "$result"
10 | exit 1
11 | fi
12 |
--------------------------------------------------------------------------------
/scripts/subsplit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
4 |
5 | cd $DIR
6 |
7 | if [ -d ".subsplit" ]; then
8 | git subsplit update
9 | else
10 | git subsplit init .
11 | fi
12 |
13 | git subsplit publish --heads="master" stubs:git@github.com:pinepain/php-ref-stubs.git
14 |
--------------------------------------------------------------------------------
/tests/001-extension_info.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | ref extension info
3 | --SKIPIF--
4 |
5 | --FILE--
6 | info();
10 |
11 | ?>
12 | --EXPECTF--
13 | ref
14 |
15 | Ref support => enabled
16 | Version => %s
17 | Revision => %s
18 | Compiled => %s @ %s
19 |
--------------------------------------------------------------------------------
/provision/apache/ports.conf:
--------------------------------------------------------------------------------
1 | # If you just change the port or add more ports here, you will likely also
2 | # have to change the VirtualHost statement in
3 | # /etc/apache2/sites-enabled/000-default.conf
4 |
5 | Listen 8080
6 |
7 |
8 | Listen 443
9 |
10 |
11 |
12 | Listen 443
13 |
14 |
15 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet
16 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-notifier_callable_string.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - callable notifier passed as string
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
22 | ?>
23 | EOF
24 | --EXPECT--
25 | Notified
26 |
27 | EOF
28 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notifier_callable_string.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - callable notifier passed as string
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
22 | ?>
23 | EOF
24 | --EXPECT--
25 | Notified
26 |
27 | EOF
28 |
--------------------------------------------------------------------------------
/stubs/src/SoftReference.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
9 | *
10 | * For the full copyright and license information, please view the
11 | * LICENSE file that was distributed with this source or visit
12 | * http://opensource.org/licenses/MIT
13 | */
14 |
15 | namespace Ref;
16 |
17 | class SoftReference extends AbstractReference
18 | {
19 | }
20 |
--------------------------------------------------------------------------------
/stubs/src/WeakReference.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
9 | *
10 | * For the full copyright and license information, please view the
11 | * LICENSE file that was distributed with this source or visit
12 | * http://opensource.org/licenses/MIT
13 | */
14 |
15 | namespace Ref;
16 |
17 | class WeakReference extends AbstractReference
18 | {
19 | }
20 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-orig_dtor_called_after_wr_dies_first.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - original object destructor called after weak reference dies first
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
21 | EOF
22 | --EXPECT--
23 | WeakTests\TrackingDtor's destructor called
24 | EOF
25 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-orig_dtor_called_after_wr_dies_first.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - original object destructor called after soft reference dies first
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
21 | EOF
22 | --EXPECT--
23 | WeakTests\TrackingDtor's destructor called
24 | EOF
25 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-orig_dtor_and_notifier_when_wr_dies_first.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - original object destructor called after weak reference dies first
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
21 | EOF
22 | --EXPECT--
23 | WeakTests\TrackingDtor's destructor called
24 | EOF
25 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-orig_dtor_and_notifier_when_wr_dies_first.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - original object destructor called after soft reference dies first
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
21 | EOF
22 | --EXPECT--
23 | WeakTests\TrackingDtor's destructor called
24 | EOF
25 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | dist: trusty
3 |
4 | language: php
5 |
6 | env:
7 | global:
8 | - NO_INTERACTION=1
9 | - TEST_TIMEOUT=120
10 |
11 | matrix:
12 | allow_failures:
13 | - php: nightly
14 |
15 | include:
16 | - php: 7.2
17 | - php: 7.2
18 | env: TEST_PHP_ARGS=-m
19 |
20 | - php: nightly
21 | # - php: nightly
22 | # env: TEST_PHP_ARGS=-m
23 |
24 | before_install:
25 | - phpize && ./configure && make
26 |
27 | script:
28 | - sh -c "make test | tee result.txt"
29 | - sh test-report.sh
30 |
31 | addons:
32 | apt:
33 | packages:
34 | - valgrind
35 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-orig_dtor_called_once.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - multiple weak references to the same object, original object destructor called once
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
22 | EOF
23 | --EXPECT--
24 | WeakTests\TrackingDtor's destructor called
25 | EOF
26 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-orig_dtor_called_once.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - multiple soft references to the same object, original object destructor called once
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
22 | EOF
23 | --EXPECT--
24 | WeakTests\TrackingDtor's destructor called
25 | EOF
26 |
--------------------------------------------------------------------------------
/tests/001-extension-loaded.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check for ref extension presence
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
20 | --EXPECT--
21 | ref extension is available
22 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-notifier_invalid_callback.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - invalid notifier callback passed
3 | --SKIPIF--
4 |
5 | --FILE--
6 | exception_export($e);
17 | }
18 |
19 | $helper->line();
20 | ?>
21 | EOF
22 | --EXPECT--
23 | TypeError: Argument 2 passed to Ref\AbstractReference::__construct() must be callable or null, string given
24 |
25 | EOF
26 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notifier_invalid_callback.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - invalid notifier callback passed
3 | --SKIPIF--
4 |
5 | --FILE--
6 | exception_export($e);
17 | }
18 |
19 | $helper->line();
20 | ?>
21 | EOF
22 | --EXPECT--
23 | TypeError: Argument 2 passed to Ref\AbstractReference::__construct() must be callable or null, string given
24 |
25 | EOF
26 |
--------------------------------------------------------------------------------
/php_ref_functions.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the pinepain/php-ref PHP extension.
3 | *
4 | * Copyright (c) 2016-2018 Bogdan Padalko
5 | *
6 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
7 | *
8 | * For the full copyright and license information, please view the
9 | * LICENSE file that was distributed with this source or visit
10 | * http://opensource.org/licenses/MIT
11 | */
12 |
13 | #ifndef PHP_REF_FUNCTIONS_H
14 | #define PHP_REF_FUNCTIONS_H
15 |
16 | #include "php.h"
17 |
18 | #ifdef ZTS
19 | #include "TSRM.h"
20 | #endif
21 |
22 | extern const zend_function_entry php_ref_functions[];
23 |
24 | #endif /* PHP_REF_FUNCTIONS_H */
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .deps
2 | *.lo
3 | *.loT
4 | *.la
5 | .libs
6 | acinclude.m4
7 | aclocal.m4
8 | autom4te.cache
9 | build
10 | config.guess
11 | config.h
12 | config.h.in
13 | config.log
14 | config.nice
15 | config.status
16 | config.sub
17 | configure
18 | configure.ac
19 | configure.in
20 | include
21 | install-sh
22 | libtool
23 | ltmain.sh
24 | Makefile
25 | Makefile.fragments
26 | Makefile.global
27 | Makefile.objects
28 | missing
29 | mkinstalldirs
30 | modules
31 | run-tests.php
32 |
33 | confdefs.h
34 | conftest
35 | conftest.c
36 | conftest.err
37 | tmp-php.ini
38 |
39 | tests/*
40 | !tests/*.phpt
41 | !tests/.testsuite.php
42 | !tests/.stubs.php
43 |
44 | /.subsplit
45 | /.vagrant
46 |
47 | ref-*.tgz
48 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-orig_dtor_called.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - original object destructor called but notifier not when weak reference dies first
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
24 | EOF
25 | --EXPECT--
26 | WeakTests\TrackingDtor's destructor called
27 | EOF
28 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-orig_dtor_called.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - original object destructor called but notifier not when soft reference dies first
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
24 | EOF
25 | --EXPECT--
26 | WeakTests\TrackingDtor's destructor called
27 | EOF
28 |
--------------------------------------------------------------------------------
/stubs/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pinepain/php-ref-stubs",
3 | "type": "library",
4 | "description": "Stub files for pinepain/php-ref php extension",
5 | "keywords": [
6 | "dev",
7 | "stub",
8 | "php-ref",
9 | "soft",
10 | "weak",
11 | "ref",
12 | "reference",
13 | "softref",
14 | "weakref",
15 | "weakreference",
16 | "softreference"
17 | ],
18 | "homepage": "https://github.com/pinepain/php-ref-stubs",
19 | "license": "MIT",
20 | "authors": [
21 | {
22 | "name": "Bogdan Padalko",
23 | "email": "pinepain@gmail.com",
24 | "homepage": "https://github.com/pinepain"
25 | }
26 | ],
27 | "require": {
28 | "php": "~7.2"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-extended_dtor_called.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - dump representation of extended reference class
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
27 | ?>
28 | EOF
29 | --EXPECT--
30 | Dtoring ExtendedWeakReferenceTrackingDtor
31 |
32 | EOF
33 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-extended_dtor_called.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - dump representation of extended reference class
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
27 | ?>
28 | EOF
29 | --EXPECT--
30 | Dtoring ExtendedWeakReferenceTrackingDtor
31 |
32 | EOF
33 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-notifier_callable_array.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - callable notifier passed as array
3 | --SKIPIF--
4 |
5 | --FILE--
6 | wr = new Ref\WeakReference($obj, [$this, 'notifier']);
19 | }
20 |
21 | public function notifier()
22 | {
23 | echo 'Notified', PHP_EOL;
24 | }
25 | }
26 |
27 | $obj = new stdClass();
28 | $t = new Test($obj);
29 | $obj = null;
30 |
31 | $helper->line();
32 | ?>
33 | EOF
34 | --EXPECT--
35 | Notified
36 |
37 | EOF
38 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notifier_callable_array.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - callable notifier passed as array
3 | --SKIPIF--
4 |
5 | --FILE--
6 | wr = new Ref\SoftReference($obj, [$this, 'notifier']);
19 | }
20 |
21 | public function notifier()
22 | {
23 | echo 'Notified', PHP_EOL;
24 | }
25 | }
26 |
27 | $obj = new stdClass();
28 | $t = new Test($obj);
29 | $obj = null;
30 |
31 | $helper->line();
32 | ?>
33 | EOF
34 | --EXPECT--
35 | Notified
36 |
37 | EOF
38 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-exception-before-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - exception thrown outside notifier before destructing
3 | --SKIPIF--
4 |
5 | --FILE--
6 | exception_export($e);
28 | }
29 |
30 | ?>
31 | EOF
32 | --EXPECT--
33 | Weak notifier called
34 | RuntimeException: Test exception
35 | EOF
36 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-exception-before-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - exception thrown outside notifier before destructing
3 | --SKIPIF--
4 |
5 | --FILE--
6 | exception_export($e);
28 | }
29 |
30 | ?>
31 | EOF
32 | --EXPECT--
33 | Soft notifier called
34 | RuntimeException: Test exception
35 | EOF
36 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.1)
2 | project(php-ref)
3 |
4 | # NOTE: This CMake file is just for syntax highlighting in CLion
5 |
6 | include_directories(/usr/local/include/php)
7 | include_directories(/usr/local/include/php/TSRM)
8 | include_directories(/usr/local/include/php/Zend)
9 | include_directories(/usr/local/include/php/ext)
10 | include_directories(/usr/local/include/php/main)
11 | include_directories(/usr/local/include/php/sapi)
12 |
13 | add_definitions(-DCOMPILE_DL_REF)
14 |
15 | set(SOURCE_FILES
16 | php_ref.h
17 | ref.c
18 |
19 | php_ref_notifier_exception.c
20 | php_ref_notifier_exception.h
21 |
22 | php_ref_reference.c
23 | php_ref_reference.h
24 |
25 | php_ref_functions.c
26 | php_ref_functions.h
27 | )
28 |
29 | add_executable(php_ref ${SOURCE_FILES})
30 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-multiple_obj.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - track only single specific object
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
26 | $obj0 = null;
27 |
28 |
29 | ?>
30 | EOF
31 | --EXPECT--
32 | WeakTests\TrackingDtor's destructor called
33 |
34 | WeakTests\TrackingDtor's destructor called
35 | Weak notifier called
36 | EOF
37 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-multiple_obj.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - track only single specific object
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
26 | $obj0 = null;
27 |
28 |
29 | ?>
30 | EOF
31 | --EXPECT--
32 | WeakTests\TrackingDtor's destructor called
33 |
34 | Weak notifier called
35 | WeakTests\TrackingDtor's destructor called
36 | EOF
37 |
--------------------------------------------------------------------------------
/tests/002-NotifierException-basic.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\NotifierException - basic
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
15 | EOF
16 | --EXPECTF--
17 | object(Ref\NotifierException)#1 (8) {
18 | ["message":protected]=>
19 | string(4) "Test"
20 | ["string":"Exception":private]=>
21 | string(0) ""
22 | ["code":protected]=>
23 | int(0)
24 | ["file":protected]=>
25 | string(%d) "%s"
26 | ["line":protected]=>
27 | int(5)
28 | ["trace":"Exception":private]=>
29 | array(0) {
30 | }
31 | ["previous":"Exception":private]=>
32 | NULL
33 | ["exceptions":"Ref\NotifierException":private]=>
34 | array(0) {
35 | }
36 | }
37 | EOF
38 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notified_with_weak.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - soft reference notifier then original object dtor and then soft notifiers called
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
27 | EOF
28 | --EXPECT--
29 | Soft notifier called
30 | WeakTests\TrackingDtor's destructor called
31 | Weak notifier called
32 | EOF
33 |
--------------------------------------------------------------------------------
/php_ref_notifier_exception.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the pinepain/php-ref PHP extension.
3 | *
4 | * Copyright (c) 2016-2018 Bogdan Padalko
5 | *
6 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
7 | *
8 | * For the full copyright and license information, please view the
9 | * LICENSE file that was distributed with this source or visit
10 | * http://opensource.org/licenses/MIT
11 | */
12 |
13 | #ifndef PHP_REF_NOTIFIER_EXCEPTION_H
14 | #define PHP_REF_NOTIFIER_EXCEPTION_H
15 |
16 | #include "php.h"
17 |
18 | #ifdef ZTS
19 | #include "TSRM.h"
20 | #endif
21 |
22 | extern zend_class_entry *php_ref_notifier_exception_class_entry;
23 |
24 | void php_ref_create_notifier_exception(zval *exception, const char *message, zval *thrown);
25 |
26 | PHP_MINIT_FUNCTION(php_ref_notifier_exception);
27 |
28 |
29 | #endif /* PHP_REF_NOTIFIER_EXCEPTION_H */
30 |
--------------------------------------------------------------------------------
/stubs/src/NotifierException.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
9 | *
10 | * For the full copyright and license information, please view the
11 | * LICENSE file that was distributed with this source or visit
12 | * http://opensource.org/licenses/MIT
13 | */
14 |
15 |
16 | namespace Ref;
17 |
18 |
19 | use Exception;
20 | use Throwable;
21 |
22 |
23 | class NotifierException extends Exception
24 | {
25 | private $exceptions = [];
26 |
27 | /**
28 | * Get exceptions that were thrown from notifiers
29 | *
30 | * @return Throwable[]
31 | */
32 | public function getExceptions(): array
33 | {
34 | return $this->exceptions;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - notifier accessor
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier is null by default', $wr0->notifier(), null);
20 | $helper->assert('Null notifier acceptable', $wr1->notifier(), null);
21 | $helper->assert('Callback notifier acceptable', $wr2->notifier(), $callback_notifier);
22 |
23 | $helper->line();
24 | ?>
25 | EOF
26 | --EXPECT--
27 | Notifier is null by default: ok
28 | Null notifier acceptable: ok
29 | Callback notifier acceptable: ok
30 |
31 | EOF
32 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - notifier accessor
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier is null by default', $sr0->notifier(), null);
20 | $helper->assert('Null notifier acceptable', $sr1->notifier(), null);
21 | $helper->assert('Callback notifier acceptable', $sr2->notifier(), $callback_notifier);
22 |
23 | $helper->line();
24 | ?>
25 | EOF
26 | --EXPECT--
27 | Notifier is null by default: ok
28 | Null notifier acceptable: ok
29 | Callback notifier acceptable: ok
30 |
31 | EOF
32 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-exception_in_callback.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - exception thrown in callback
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
26 | }
27 |
28 | ?>
29 | EOF
30 | --EXPECT--
31 | WeakTests\TrackingDtor's destructor called
32 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
33 | thrown:
34 | #0: Exception: Test exception from callback
35 | EOF
36 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-exception_in_callback.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - exception thrown in callback
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
26 | }
27 |
28 | ?>
29 | EOF
30 | --EXPECT--
31 | WeakTests\TrackingDtor's destructor called
32 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
33 | thrown:
34 | #0: Exception: Test exception from callback
35 | EOF
36 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-multiple_with_notify_and_orig_dtor.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - multiple weak references with notifiers, original object destructor called once and after all notifiers
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
29 | EOF
30 | --EXPECT--
31 | WeakTests\TrackingDtor's destructor called
32 | Weak notifier 2 called
33 | Weak notifier 1 called
34 | EOF
35 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-serialize_extended_not_allowed.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - serialize extended reference that tries to implemet Serializable interface is not allowed
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
32 | EOF
33 | --EXPECT--
34 | Fatal error: Class SerializableWeakReference could not implement interface Serializable in Unknown on line 0
35 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-multiple_with_notify_and_orig_dtor.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - multiple soft references with notifiers, original object destructor called once and after all notifiers
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
29 | EOF
30 | --EXPECT--
31 | Weak notifier 2 called
32 | Weak notifier 1 called
33 | WeakTests\TrackingDtor's destructor called
34 | EOF
35 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-serialize_extended_not_allowed.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - serialize extended reference that tries to implemet Serializable interface is not allowed
3 | --SKIPIF--
4 |
5 | --FILE--
6 |
32 | EOF
33 | --EXPECT--
34 | Fatal error: Class SerializableWeakReference could not implement interface Serializable in Unknown on line 0
35 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-die_in_dtor.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - destructor calls die()
3 | --SKIPIF--
4 |
5 | --FILE--
6 | exception_export($e);
32 | $helper->line();
33 | }
34 |
35 | register_shutdown_function(function () use (&$wr, &$helper) {
36 | echo 'We did not die properly', PHP_EOL;
37 | });
38 |
39 |
40 | ?>
41 | EOF
42 | --EXPECT--
43 | Destructor dies
44 |
--------------------------------------------------------------------------------
/tests/005-Soft-and-Weak-Reference-exception-before-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference + Ref\WeakReference - exception thrown outside notifier before destructing
3 | --SKIPIF--
4 |
5 | --FILE--
6 | exception_export($e);
33 | }
34 |
35 | ?>
36 | EOF
37 | --EXPECT--
38 | Soft notifier called
39 | Weak notifier called
40 | RuntimeException: Test exception
41 | EOF
42 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-exception-before-and-from-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - exception thrown outside notifier before destructing and in notifier
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
29 | }
30 |
31 | ?>
32 | EOF
33 | --EXPECT--
34 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
35 | previous: RuntimeException: Test exception
36 | thrown:
37 | #0: RuntimeException: From weak notifier
38 | EOF
39 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-exception-before-and-from-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - exception thrown outside notifier before destructing and in notifier
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
29 | }
30 |
31 | ?>
32 | EOF
33 | --EXPECT--
34 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
35 | previous: RuntimeException: Test exception
36 | thrown:
37 | #0: RuntimeException: From soft notifier
38 | EOF
39 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-die_in_dtor.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - destructor calls die()
3 | --SKIPIF--
4 |
5 | --FILE--
6 | exception_export($e);
32 | $helper->line();
33 | }
34 |
35 | register_shutdown_function(function () use (&$sr, &$helper) {
36 | echo 'We did not die properly', PHP_EOL;
37 | });
38 |
39 |
40 | ?>
41 | EOF
42 | --EXPECT--
43 | Soft notifier called
44 | Destructor dies
45 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-exception_in_orig_dtor.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - exception thrown in orig dtor
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
33 | }
34 |
35 | ?>
36 | EOF
37 | --EXPECT--
38 | Dtor called
39 | Weak callback called
40 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
41 | thrown:
42 | #0: Exception: Test exception from dtor
43 | EOF
44 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-exception_in_orig_dtor.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - exception thrown in orig dtor
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
33 | }
34 |
35 | ?>
36 | EOF
37 | --EXPECT--
38 | Weak callback called
39 | Dtor called
40 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
41 | thrown:
42 | #0: Exception: Test exception from dtor
43 | EOF
44 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-orig_dtor_and_notify.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - original object destructor called with notify callback before it
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert("Weak references points to original object", $wr->get() === $obj);
23 |
24 | $helper->line();
25 | $obj = null;
26 | $helper->line();
27 |
28 | $helper->assert("Weak references points to null", $wr->get() === null);
29 |
30 | $obj = null;
31 |
32 | ?>
33 | EOF
34 | --EXPECT--
35 | Weak references points to original object: ok
36 |
37 | WeakTests\TrackingDtor's destructor called
38 | Weak notifier called
39 |
40 | Weak references points to null: ok
41 | EOF
42 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-orig_dtor_and_notify.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - original object destructor called with notify callback after it
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert("Weak references points to original object", $sr->get() === $obj);
23 |
24 | $helper->line();
25 | $obj = null;
26 | $helper->line();
27 |
28 | $helper->assert("Weak references points to null", $sr->get() === null);
29 |
30 | $obj = null;
31 |
32 | ?>
33 | EOF
34 | --EXPECT--
35 | Weak references points to original object: ok
36 |
37 | Weak notifier called
38 | WeakTests\TrackingDtor's destructor called
39 |
40 | Weak references points to null: ok
41 | EOF
42 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-notified.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - weak reference notified when object destroyed
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier called', true);
15 | $helper->assert('Notifier get 1 argument', sizeof(func_get_args()) === 1);
16 | $helper->assert('Notifier get weak reference as it argument', $reference instanceof Ref\WeakReference);
17 | $helper->assert('Original object is null', null === $obj);
18 | $helper->assert('Weak reference in notifier is null', null === $reference->get());
19 | });
20 |
21 | $obj = null;
22 |
23 | ?>
24 | EOF
25 | --EXPECT--
26 | Notifier called: ok
27 | Notifier get 1 argument: ok
28 | Notifier get weak reference as it argument: ok
29 | Original object is null: ok
30 | Weak reference in notifier is null: ok
31 | EOF
32 |
--------------------------------------------------------------------------------
/stubs/README.md:
--------------------------------------------------------------------------------
1 | # Stub files for [php-ref](https://github.com/pinepain/php-ref) PHP extension
2 |
3 | This is a git subtree split of [php-ref](https://github.com/pinepain/php-ref) extension stub files.
4 |
5 | **All issues and pull-requests should be submitted to the original [php-ref](https://github.com/pinepain/php-ref) repository.**
6 |
7 | ### PLEASE READ:
8 |
9 | Maintaining this project takes significant amount of time and efforts.
10 | If you like my work and want to show your appreciation, please consider supporting me at https://www.patreon.com/pinepain.
11 |
12 | ## Installation
13 |
14 | If you are also using Composer, it is recommended that you add the [php-ref-stub](https://github.com/pinepain/php-ref-stubs)
15 | package as a dev-mode requirement. It provides skeleton definitions and annotations to enable support for auto-completion
16 | in your IDE and other code-analysis tools.
17 |
18 | composer require --dev pinepain/php-ref-stubs
19 |
20 |
21 | ## License
22 |
23 | [php-ref](https://github.com/pinepain/php-ref) PHP extension is licensed under the [MIT license](http://opensource.org/licenses/MIT).
24 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notified_prevent_destoying_forever_with_weak.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - prevent original object from being destroyed, soft notifiers called only when soft ref released
3 | --SKIPIF--
4 |
5 | --FILE--
6 | get();
21 | });
22 |
23 | $wr = new Ref\WeakReference($obj, function (Ref\WeakReference $reference){
24 | echo 'Weak notifier called', PHP_EOL;
25 | });
26 |
27 | $obj = null;
28 | $sr = null;
29 |
30 | echo 'Here original dtor will be called', PHP_EOL;
31 | $obj_copy = null;
32 |
33 | ?>
34 | EOF
35 | --EXPECT--
36 | Soft notifier called
37 | Here original dtor will be called
38 | WeakTests\TrackingDtor's destructor called
39 | Weak notifier called
40 | EOF
41 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-serialize_not_allowed.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - serialize reference
3 | --SKIPIF--
4 |
5 | --FILE--
6 | dump($wr);
15 |
16 | try {
17 | $serialized = serialize($wr);
18 | $helper->dump($serialized);
19 | } catch (\Throwable $e) {
20 | $helper->exception_export($e);
21 | }
22 |
23 | $helper->line();
24 |
25 | ?>
26 | EOF
27 | --EXPECT--
28 | object(Ref\WeakReference)#3 (2) refcount(3){
29 | ["referent":"Ref\AbstractReference":private]=>
30 | object(stdClass)#2 (0) refcount(2){
31 | }
32 | ["notifier":"Ref\AbstractReference":private]=>
33 | object(Closure)#4 (1) refcount(2){
34 | ["parameter"]=>
35 | array(1) refcount(1){
36 | ["$reference"]=>
37 | string(10) "" refcount(1)
38 | }
39 | }
40 | }
41 | Exception: Serialization of 'Ref\WeakReference' is not allowed
42 |
43 | EOF
44 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notified_prevent_destoying_with_weak.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - prevent original object from being destroyed forever, soft notifiers will not be called
3 | --SKIPIF--
4 |
5 | --FILE--
6 | get();
21 | });
22 |
23 | $wr = new Ref\WeakReference($obj, function (Ref\WeakReference $reference){
24 | echo 'Weak notifier called', PHP_EOL;
25 | });
26 |
27 | $obj = null;
28 | //$sr = null;
29 |
30 | echo 'Here soft reference notifier will be called', PHP_EOL;
31 | $obj_copy = null;
32 |
33 | ?>
34 | EOF
35 | --EXPECT--
36 | Soft notifier called
37 | Here soft reference notifier will be called
38 | Soft notifier called
39 | EOF
40 | WeakTests\TrackingDtor's destructor called
41 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-serialize_not_allowed.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - serialize reference
3 | --SKIPIF--
4 |
5 | --FILE--
6 | dump($sr);
15 |
16 | try {
17 | $serialized = serialize($sr);
18 | $helper->dump($serialized);
19 | } catch (\Throwable $e) {
20 | $helper->exception_export($e);
21 | }
22 |
23 | $helper->line();
24 |
25 | ?>
26 | EOF
27 | --EXPECT--
28 | object(Ref\SoftReference)#3 (2) refcount(3){
29 | ["referent":"Ref\AbstractReference":private]=>
30 | object(stdClass)#2 (0) refcount(2){
31 | }
32 | ["notifier":"Ref\AbstractReference":private]=>
33 | object(Closure)#4 (1) refcount(2){
34 | ["parameter"]=>
35 | array(1) refcount(1){
36 | ["$reference"]=>
37 | string(10) "" refcount(1)
38 | }
39 | }
40 | }
41 | Exception: Serialization of 'Ref\SoftReference' is not allowed
42 |
43 | EOF
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2016-2018 Bogdan Padalko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 | of the Software, and to permit persons to whom the Software is furnished to do
10 | so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/stubs/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2016-2018 Bogdan Padalko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 | of the Software, and to permit persons to whom the Software is furnished to do
10 | so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-exception_in_orig_dtor_and_callback.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - exception thrown in orig dtor and callback
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
36 | }
37 |
38 | ?>
39 | EOF
40 | --EXPECT--
41 | Dtor called
42 | Callback called
43 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
44 | thrown:
45 | #0: Exception: Test exception from dtor
46 | #1: Exception: Test exception from callback
47 | EOF
48 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-exception_in_orig_dtor_and_callback.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - exception thrown in orig dtor and callback
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
36 | }
37 |
38 | ?>
39 | EOF
40 | --EXPECT--
41 | Callback called
42 | Dtor called
43 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
44 | thrown:
45 | #0: Exception: Test exception from callback
46 | #1: Exception: Test exception from dtor
47 | EOF
48 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-notifier_clone_change.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - change notifier on cloned object
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier is callback', $wr->notifier(), $callback_notifier_1);
23 |
24 | $wr1 = clone $wr;
25 | $helper->assert('Cloned notifier is array', $wr1->notifier(), $callback_notifier_1);
26 | $wr1->notifier($callback_notifier_2);
27 | $helper->assert('Cloned notifier changed to it own callback', $wr1->notifier(), $callback_notifier_2);
28 |
29 | $helper->line();
30 | $obj = null;
31 | $helper->line();
32 | ?>
33 | EOF
34 | --EXPECT--
35 | Notifier is callback: ok
36 | Cloned notifier is array: ok
37 | Cloned notifier changed to it own callback: ok
38 |
39 | Callback notifier 2
40 | Callback notifier 1
41 |
42 | EOF
43 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notifier_clone_change.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - change notifier on cloned object
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier is callback', $sr->notifier(), $callback_notifier_1);
23 |
24 | $sr1 = clone $sr;
25 | $helper->assert('Cloned notifier is array', $sr1->notifier(), $callback_notifier_1);
26 | $sr1->notifier($callback_notifier_2);
27 | $helper->assert('Cloned notifier changed to it own callback', $sr1->notifier(), $callback_notifier_2);
28 |
29 | $helper->line();
30 | $obj = null;
31 | $helper->line();
32 | ?>
33 | EOF
34 | --EXPECT--
35 | Notifier is callback: ok
36 | Cloned notifier is array: ok
37 | Cloned notifier changed to it own callback: ok
38 |
39 | Callback notifier 2
40 | Callback notifier 1
41 |
42 | EOF
43 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-multiple_weak.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - multiple weak references to the same object
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert("First weak references points to original object", $wr1->get() === $obj);
21 | $helper->assert("Second weak references points to original object", $wr2->get() === $obj);
22 |
23 | $helper->line();
24 | $obj = null;
25 | $helper->line();
26 |
27 | $helper->assert("First weak references points to null", $wr1->get() === null);
28 | $helper->assert("Second weak references points to null", $wr2->get() === null);
29 |
30 | $wr1 = null;
31 | $wr2 = null;
32 |
33 | ?>
34 | EOF
35 | --EXPECT--
36 | First weak references points to original object: ok
37 | Second weak references points to original object: ok
38 |
39 | WeakTests\TrackingDtor's destructor called
40 |
41 | First weak references points to null: ok
42 | Second weak references points to null: ok
43 | EOF
44 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-multiple_weak.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - multiple soft references to the same object
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert("First soft references points to original object", $sr1->get() === $obj);
21 | $helper->assert("Second soft references points to original object", $sr2->get() === $obj);
22 |
23 | $helper->line();
24 | $obj = null;
25 | $helper->line();
26 |
27 | $helper->assert("First soft references points to null", $sr1->get() === null);
28 | $helper->assert("Second soft references points to null", $sr2->get() === null);
29 |
30 | $sr1 = null;
31 | $sr2 = null;
32 |
33 | ?>
34 | EOF
35 | --EXPECT--
36 | First soft references points to original object: ok
37 | Second soft references points to original object: ok
38 |
39 | WeakTests\TrackingDtor's destructor called
40 |
41 | First soft references points to null: ok
42 | Second soft references points to null: ok
43 | EOF
44 |
--------------------------------------------------------------------------------
/tests/005-Soft-and-Weak-Reference-exception-before-and-from-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference + Ref\WeakReference - exception thrown outside notifier before destructing and in notifier
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
34 | }
35 |
36 | ?>
37 | EOF
38 | --EXPECT--
39 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
40 | previous: RuntimeException: Test exception
41 | thrown:
42 | #0: RuntimeException: From soft notifier
43 | #1: RuntimeException: From weak notifier
44 | EOF
45 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notified.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - soft reference notified when object destroyed
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier called', true);
15 | $helper->assert('Notifier get 1 argument', sizeof(func_get_args()) === 1);
16 | $helper->assert('Notifier get soft reference as it argument', $reference instanceof Ref\SoftReference);
17 | $helper->assert('Original object is null', null === $obj);
18 | $helper->assert('Soft reference in notifier is not null', null !== $reference->get());
19 | $helper->assert('Soft reference in notifier points to original object', $reference->get() instanceof stdClass);
20 | });
21 |
22 | $obj = null;
23 |
24 | ?>
25 | EOF
26 | --EXPECT--
27 | Notifier called: ok
28 | Notifier get 1 argument: ok
29 | Notifier get soft reference as it argument: ok
30 | Original object is null: ok
31 | Soft reference in notifier is not null: ok
32 | Soft reference in notifier points to original object: ok
33 | EOF
34 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notified_prevent_destoying_multiple.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - do not call later soft notifiers when object was prevented from being destroyed
3 | --SKIPIF--
4 |
5 | --FILE--
6 | get();
31 | }
32 | });
33 |
34 |
35 | $obj = null;
36 | $obj_copy = null;
37 |
38 | ?>
39 | EOF
40 | --EXPECT--
41 | Backup soft notifier called
42 | Original object was prevented from being destroyed
43 | Backup soft notifier called
44 | Soft notifier called
45 | WeakTests\TrackingDtor's destructor called
46 | EOF
47 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-notifier_not_called_after_wr_dies_first.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - notifier not called after weak reference dies first
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
30 | $helper->line();
31 | }
32 |
33 | $helper->assert('Referent object dead', $wr->get() === null);
34 | $helper->assert('Referent object invalid', $wr->valid(), false);
35 | $helper->line();
36 |
37 | ?>
38 | EOF
39 | --EXPECT--
40 | Weak notifier called
41 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
42 | thrown:
43 | #0: Exception: Destructor throws exception
44 |
45 | Referent object dead: ok
46 | Referent object invalid: ok
47 |
48 | EOF
49 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notifier_not_called_after_wr_dies_first.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - notifier not called after weak reference dies first
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
30 | $helper->line();
31 | }
32 |
33 | $helper->assert('Referent object dead', $sr->get() === null);
34 | $helper->assert('Referent object invalid', $sr->valid(), false);
35 | $helper->line();
36 |
37 | ?>
38 | EOF
39 | --EXPECT--
40 | Weak notifier called
41 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
42 | thrown:
43 | #0: Exception: Destructor throws exception
44 |
45 | Referent object dead: ok
46 | Referent object invalid: ok
47 |
48 | EOF
49 |
--------------------------------------------------------------------------------
/tests/001-verify-method-case.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check whether all methods follows naming convention
3 | --SKIPIF--
4 |
5 | --FILE--
6 | getClasses();
10 |
11 |
12 | class MethodsCaseVerifier
13 | {
14 | private $invalid = [];
15 |
16 | public function verifyClass(ReflectionClass $class)
17 | {
18 | foreach ($class->getMethods() as $m) {
19 | $this->verifyMethod($m);
20 | }
21 | }
22 |
23 | public function verifyMethod(ReflectionMethod $method)
24 | {
25 | if (strtolower($method->getName()[0]) == $method->getName()[0]) {
26 | return;
27 | }
28 |
29 | $method_name = $method->getDeclaringClass()->getName() . '::' . $method->getName();
30 |
31 | if (isset($this->invalid[$method_name])) {
32 | return;
33 | }
34 |
35 | $this->invalid[$method_name] = true;
36 |
37 | echo "{$method_name}() - invalid method name", PHP_EOL;
38 | }
39 |
40 | public function isValid()
41 | {
42 | return empty($this->invalid);
43 | }
44 | }
45 |
46 | $v = new MethodsCaseVerifier();
47 |
48 |
49 | foreach ($classes as $c) {
50 | $v->verifyClass($c);
51 | }
52 |
53 | if ($v->isValid()) {
54 | echo 'All methods are valid', PHP_EOL;
55 | }
56 |
57 | ?>
58 | --EXPECT--
59 | All methods are valid
60 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-reference-deleted-during-notifier.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - reference deleted during notifier call
3 | --SKIPIF--
4 |
5 | --FILE--
6 | storage[$hash]);
20 | var_dump($this);
21 | });
22 |
23 | $this->storage[$hash] = $key;
24 | }
25 | }
26 |
27 | $map = new Test();
28 |
29 | $key_1 = new stdClass();
30 | $value_1 = new stdClass();
31 |
32 | $map->put($key_1, $value_1, 'test');
33 |
34 | $key_1 = null;
35 | ?>
36 | --EXPECT--
37 | {closure}
38 | object(Test)#1 (1) {
39 | ["storage"]=>
40 | array(1) {
41 | ["test"]=>
42 | object(Ref\WeakReference)#4 (2) {
43 | ["referent":"Ref\AbstractReference":private]=>
44 | NULL
45 | ["notifier":"Ref\AbstractReference":private]=>
46 | object(Closure)#5 (2) {
47 | ["static"]=>
48 | array(1) {
49 | ["hash"]=>
50 | string(4) "test"
51 | }
52 | ["this"]=>
53 | *RECURSION*
54 | }
55 | }
56 | }
57 | }
58 | object(Test)#1 (1) {
59 | ["storage"]=>
60 | array(0) {
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/provision/apache/000-default.conf:
--------------------------------------------------------------------------------
1 |
2 | # The ServerName directive sets the request scheme, hostname and port that
3 | # the server uses to identify itself. This is used when creating
4 | # redirection URLs. In the context of virtual hosts, the ServerName
5 | # specifies what hostname must appear in the request's Host: header to
6 | # match this virtual host. For the default virtual host (this file) this
7 | # value is not decisive as it is used as a last resort host regardless.
8 | # However, you must set it for any further virtual host explicitly.
9 | #ServerName www.example.com
10 |
11 | ServerAdmin webmaster@localhost
12 | DocumentRoot /var/www/html
13 |
14 | DirectoryIndex index.php index-apache.html
15 |
16 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
17 | # error, crit, alert, emerg.
18 | # It is also possible to configure the loglevel for particular
19 | # modules, e.g.
20 | #LogLevel info ssl:warn
21 |
22 | ErrorLog ${APACHE_LOG_DIR}/error.log
23 | CustomLog ${APACHE_LOG_DIR}/access.log combined
24 |
25 | # For most configuration files from conf-available/, which are
26 | # enabled or disabled at a global level, it is possible to
27 | # include a line for only one particular virtual host. For example the
28 | # following line enables the CGI configuration for this host only
29 | # after it has been globally disabled with "a2disconf".
30 | #Include conf-available/serve-cgi-bin.conf
31 |
32 |
33 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet
34 |
--------------------------------------------------------------------------------
/php_ref.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the pinepain/php-ref PHP extension.
3 | *
4 | * Copyright (c) 2016-2018 Bogdan Padalko
5 | *
6 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
7 | *
8 | * For the full copyright and license information, please view the
9 | * LICENSE file that was distributed with this source or visit
10 | * http://opensource.org/licenses/MIT
11 | */
12 |
13 | #ifndef PHP_REF_H
14 | #define PHP_REF_H
15 |
16 | #include "php.h"
17 |
18 | extern zend_module_entry php_ref_module_entry;
19 | #define phpext_ref_ptr &php_ref_module_entry
20 |
21 | #ifndef PHP_REF_VERSION
22 | #define PHP_REF_VERSION "0.7.0"
23 | #endif
24 |
25 | #ifndef PHP_REF_REVISION
26 | #define PHP_REF_REVISION "dev"
27 | #endif
28 |
29 | #if PHP_VERSION_ID < 70200
30 | // should never get her, but just in case
31 | #error PHP >= 7.2 required
32 | #endif
33 |
34 | #define PHP_REF_NS "Ref"
35 |
36 | #ifdef PHP_WIN32
37 | # define PHP_REF_API __declspec(dllexport)
38 | #elif defined(__GNUC__) && __GNUC__ >= 4
39 | # define PHP_REF_API __attribute__ ((visibility("default")))
40 | #else
41 | # define PHP_REF_API
42 | #endif
43 |
44 |
45 | #ifdef ZTS
46 | #include "TSRM.h"
47 | #endif
48 |
49 | ZEND_BEGIN_MODULE_GLOBALS(ref)
50 | HashTable *referents;
51 | ZEND_END_MODULE_GLOBALS(ref)
52 |
53 | ZEND_EXTERN_MODULE_GLOBALS(ref);
54 | #define PHP_REF_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(ref, v)
55 |
56 | #if defined(ZTS) && defined(COMPILE_DL_REF)
57 | ZEND_TSRMLS_CACHE_EXTERN();
58 | #endif
59 |
60 | #endif /* PHP_REF_H */
61 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-basic.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - dump representation, get() and valid() methods
3 | --SKIPIF--
4 |
5 | --FILE--
6 | header('When referent object alive');
16 | $helper->assert('Referent object alive', $wr->get() === $obj);
17 | $helper->assert('Referent object valid', $wr->valid());
18 | $helper->dump($wr);
19 | $helper->space();
20 |
21 | $obj = null;
22 |
23 |
24 | $helper->header('When referent object dead');
25 | $helper->assert('Referent object dead', $wr->get() === null);
26 | $helper->assert('Referent object invalid', $wr->valid(), false);
27 | $helper->dump($wr);
28 | $helper->line();
29 | ?>
30 | EOF
31 | --EXPECT--
32 | When referent object alive:
33 | ---------------------------
34 | Referent object alive: ok
35 | Referent object valid: ok
36 | object(Ref\WeakReference)#3 (2) refcount(3){
37 | ["referent":"Ref\AbstractReference":private]=>
38 | object(stdClass)#2 (0) refcount(2){
39 | }
40 | ["notifier":"Ref\AbstractReference":private]=>
41 | NULL
42 | }
43 |
44 |
45 | When referent object dead:
46 | --------------------------
47 | Referent object dead: ok
48 | Referent object invalid: ok
49 | object(Ref\WeakReference)#3 (2) refcount(3){
50 | ["referent":"Ref\AbstractReference":private]=>
51 | NULL
52 | ["notifier":"Ref\AbstractReference":private]=>
53 | NULL
54 | }
55 |
56 | EOF
57 |
--------------------------------------------------------------------------------
/tests/004-SofReference-basic.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - dump representation, get() and valid() methods
3 | --SKIPIF--
4 |
5 | --FILE--
6 | header('When referent object alive');
16 | $helper->assert('Referent object alive', $ref->get() === $obj);
17 | $helper->assert('Referent object valid', $ref->valid());
18 | $helper->dump($ref);
19 | $helper->space();
20 |
21 | $obj = null;
22 |
23 |
24 | $helper->header('When referent object dead');
25 | $helper->assert('Referent object dead', $ref->get() === null);
26 | $helper->assert('Referent object invalid', $ref->valid(), false);
27 | $helper->dump($ref);
28 | $helper->line();
29 | ?>
30 | EOF
31 | --EXPECT--
32 | When referent object alive:
33 | ---------------------------
34 | Referent object alive: ok
35 | Referent object valid: ok
36 | object(Ref\SoftReference)#3 (2) refcount(3){
37 | ["referent":"Ref\AbstractReference":private]=>
38 | object(stdClass)#2 (0) refcount(2){
39 | }
40 | ["notifier":"Ref\AbstractReference":private]=>
41 | NULL
42 | }
43 |
44 |
45 | When referent object dead:
46 | --------------------------
47 | Referent object dead: ok
48 | Referent object invalid: ok
49 | object(Ref\SoftReference)#3 (2) refcount(3){
50 | ["referent":"Ref\AbstractReference":private]=>
51 | NULL
52 | ["notifier":"Ref\AbstractReference":private]=>
53 | NULL
54 | }
55 |
56 | EOF
57 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-dump_extended.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - dump representation of extended reference class
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
21 |
22 | $obj = null;
23 |
24 | var_dump($wr);
25 | $helper->line();
26 | ?>
27 | EOF
28 | --EXPECT--
29 | object(WeakTests\ExtendedWeakReference)#3 (3) {
30 | ["test":"WeakTests\ExtendedWeakReference":private]=>
31 | array(1) {
32 | [0]=>
33 | int(42)
34 | }
35 | ["referent":"Ref\AbstractReference":private]=>
36 | object(stdClass)#2 (0) {
37 | }
38 | ["notifier":"Ref\AbstractReference":private]=>
39 | object(Closure)#4 (1) {
40 | ["parameter"]=>
41 | array(1) {
42 | ["$reference"]=>
43 | string(10) ""
44 | }
45 | }
46 | }
47 |
48 | object(WeakTests\ExtendedWeakReference)#3 (3) {
49 | ["test":"WeakTests\ExtendedWeakReference":private]=>
50 | array(1) {
51 | [0]=>
52 | int(42)
53 | }
54 | ["referent":"Ref\AbstractReference":private]=>
55 | NULL
56 | ["notifier":"Ref\AbstractReference":private]=>
57 | object(Closure)#4 (1) {
58 | ["parameter"]=>
59 | array(1) {
60 | ["$reference"]=>
61 | string(10) ""
62 | }
63 | }
64 | }
65 |
66 | EOF
67 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-dump_extended.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - dump representation of extended reference class
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
21 |
22 | $obj = null;
23 |
24 | var_dump($sr);
25 | $helper->line();
26 | ?>
27 | EOF
28 | --EXPECT--
29 | object(WeakTests\ExtendedSoftReference)#3 (3) {
30 | ["test":"WeakTests\ExtendedSoftReference":private]=>
31 | array(1) {
32 | [0]=>
33 | int(42)
34 | }
35 | ["referent":"Ref\AbstractReference":private]=>
36 | object(stdClass)#2 (0) {
37 | }
38 | ["notifier":"Ref\AbstractReference":private]=>
39 | object(Closure)#4 (1) {
40 | ["parameter"]=>
41 | array(1) {
42 | ["$reference"]=>
43 | string(10) ""
44 | }
45 | }
46 | }
47 |
48 | object(WeakTests\ExtendedSoftReference)#3 (3) {
49 | ["test":"WeakTests\ExtendedSoftReference":private]=>
50 | array(1) {
51 | [0]=>
52 | int(42)
53 | }
54 | ["referent":"Ref\AbstractReference":private]=>
55 | NULL
56 | ["notifier":"Ref\AbstractReference":private]=>
57 | object(Closure)#4 (1) {
58 | ["parameter"]=>
59 | array(1) {
60 | ["$reference"]=>
61 | string(10) ""
62 | }
63 | }
64 | }
65 |
66 | EOF
67 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5 | VAGRANTFILE_API_VERSION = "2"
6 |
7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8 | # All Vagrant configuration is done here. The most common configuration
9 | # options are documented and commented below. For a complete reference,
10 | # please see the online documentation at vagrantup.com.
11 |
12 | # Every Vagrant virtual environment requires a box to build off of.
13 | config.vm.box = "bento/ubuntu-16.04"
14 |
15 | # Disable automatic box update checking. If you disable this, then
16 | # boxes will only be checked for updates when the user runs
17 | # `vagrant box outdated`. This is not recommended.
18 | # config.vm.box_check_update = false
19 |
20 | # Create a private network, which allows host-only access to the machine
21 | # using a specific IP.
22 | config.vm.network "private_network", ip: "192.168.33.102"
23 |
24 | # NOTE: temporary workaround
25 | #config.vm.hostname = "php-ref.vagrant"
26 | config.vm.provision :shell, inline: "hostnamectl set-hostname php-ref.vagrant"
27 |
28 | config.ssh.insert_key = false
29 |
30 | config.vm.synced_folder ".", "/home/vagrant/php-ref"
31 |
32 | config.vm.provider "virtualbox" do |vb|
33 | # Don't boot with headless mode
34 | #vb.gui = true
35 |
36 | #vb.customize ["modifyvm", :id, "--memory", 2048]
37 | #vb.customize ["modifyvm", :id, "--cpus", 4]
38 | end
39 |
40 | config.vm.provision "shell", path: './provision/provision.sh', privileged: false
41 | end
42 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-spl_object_storage_debug_hash_consistent.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - SplObjectStorage hashes in debug output still consistent before and after wrapping
3 | --SKIPIF--
4 |
5 | --FILE--
6 | attach($obj);
15 | $wr = new Ref\WeakReference($obj);
16 | $current_hash = spl_object_hash($obj);
17 | $helper->assert('Stored in SplObjectStorage weak-referenced object hash matches origin one', $original_hash == $current_hash);
18 |
19 | ob_start();
20 | debug_zval_dump($s);
21 | $res = ob_get_contents();
22 | ob_end_clean();
23 |
24 | $helper->assert('Object hash in SplObjectStorage debug output not changed', false !== strpos($res, $original_hash));
25 | $helper->line();
26 |
27 | debug_zval_dump($original_hash);
28 | debug_zval_dump($current_hash);
29 | echo $res;
30 |
31 | $helper->line();
32 |
33 | ?>
34 | EOF
35 | --EXPECTF--
36 | Stored in SplObjectStorage weak-referenced object hash matches origin one: ok
37 | Object hash in SplObjectStorage debug output not changed: ok
38 |
39 | string(32) "%s" refcount(2)
40 | string(32) "%s" refcount(2)
41 | object(SplObjectStorage)#2 (1) refcount(2){
42 | ["storage":"SplObjectStorage":private]=>
43 | array(1) refcount(1){
44 | ["%s"]=>
45 | array(2) refcount(1){
46 | ["obj"]=>
47 | object(stdClass)#3 (0) refcount(2){
48 | }
49 | ["inf"]=>
50 | NULL
51 | }
52 | }
53 | }
54 |
55 | EOF
56 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-spl_object_storage_debug_hash_consistent.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - SplObjectStorage hashes in debug output still consistent before and after wrapping
3 | --SKIPIF--
4 |
5 | --FILE--
6 | attach($obj);
15 | $sr = new Ref\SoftReference($obj);
16 | $current_hash = spl_object_hash($obj);
17 | $helper->assert('Stored in SplObjectStorage soft-referenced object hash matches origin one', $original_hash == $current_hash);
18 |
19 | ob_start();
20 | debug_zval_dump($s);
21 | $res = ob_get_contents();
22 | ob_end_clean();
23 |
24 | $helper->assert('Object hash in SplObjectStorage debug output not changed', false !== strpos($res, $original_hash));
25 | $helper->line();
26 |
27 | debug_zval_dump($original_hash);
28 | debug_zval_dump($current_hash);
29 | echo $res;
30 |
31 | $helper->line();
32 |
33 | ?>
34 | EOF
35 | --EXPECTF--
36 | Stored in SplObjectStorage soft-referenced object hash matches origin one: ok
37 | Object hash in SplObjectStorage debug output not changed: ok
38 |
39 | string(32) "%s" refcount(2)
40 | string(32) "%s" refcount(2)
41 | object(SplObjectStorage)#2 (1) refcount(2){
42 | ["storage":"SplObjectStorage":private]=>
43 | array(1) refcount(1){
44 | ["%s"]=>
45 | array(2) refcount(1){
46 | ["obj"]=>
47 | object(stdClass)#3 (0) refcount(2){
48 | }
49 | ["inf"]=>
50 | NULL
51 | }
52 | }
53 | }
54 |
55 | EOF
56 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-spl_hash_consistent.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - spl_object_hash still consistent before and after wrapping
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Wrapped object hash matches origin one', $original_hash == $current_hash);
21 |
22 |
23 | $wr2 = new Ref\WeakReference($obj);
24 |
25 | $double_hash = spl_object_hash($obj);
26 | $helper->assert('Repeatedly wrapped object hash does not changes', $current_hash == $double_hash);
27 |
28 | $wr = null;
29 |
30 | $again_hash = spl_object_hash($obj);
31 | $helper->assert('Repeatedly wrapped object hash does not changes after some reference death', $current_hash == $again_hash);
32 |
33 | $wr2 = null;
34 |
35 | $nullified_hash = spl_object_hash($obj);
36 | $helper->assert('Wrapped object hash still not changed even after all references died', $current_hash == $original_hash);
37 | $helper->assert('Wrapped object hash still the same even after all references died', $current_hash == $nullified_hash);
38 |
39 | $helper->line();
40 | ?>
41 | EOF
42 | --EXPECT--
43 | Wrapped object hash matches origin one: ok
44 | Repeatedly wrapped object hash does not changes: ok
45 | Repeatedly wrapped object hash does not changes after some reference death: ok
46 | Wrapped object hash still not changed even after all references died: ok
47 | Wrapped object hash still the same even after all references died: ok
48 |
49 | EOF
50 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-spl_hash_consistent.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - spl_object_hash still consistent before and after wrapping
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Wrapped object hash matches origin one', $original_hash == $current_hash);
21 |
22 |
23 | $sr2 = new Ref\SoftReference($obj);
24 |
25 | $double_hash = spl_object_hash($obj);
26 | $helper->assert('Repeatedly wrapped object hash does not changes', $current_hash == $double_hash);
27 |
28 | $sr = null;
29 |
30 | $again_hash = spl_object_hash($obj);
31 | $helper->assert('Repeatedly wrapped object hash does not changes after some reference death', $current_hash == $again_hash);
32 |
33 | $sr2 = null;
34 |
35 | $nullified_hash = spl_object_hash($obj);
36 | $helper->assert('Wrapped object hash still not changed even after all references died', $current_hash == $original_hash);
37 | $helper->assert('Wrapped object hash still the same even after all references died', $current_hash == $nullified_hash);
38 |
39 | $helper->line();
40 | ?>
41 | EOF
42 | --EXPECT--
43 | Wrapped object hash matches origin one: ok
44 | Repeatedly wrapped object hash does not changes: ok
45 | Repeatedly wrapped object hash does not changes after some reference death: ok
46 | Wrapped object hash still not changed even after all references died: ok
47 | Wrapped object hash still the same even after all references died: ok
48 |
49 | EOF
50 |
--------------------------------------------------------------------------------
/config.m4:
--------------------------------------------------------------------------------
1 | dnl $Id$
2 | dnl config.m4 for extension ref
3 |
4 | PHP_ARG_ENABLE(ref, whether to enable ref support,
5 | dnl Make sure that the comment is aligned:
6 | [ --enable-ref Enable ref support])
7 |
8 | if test "$PHP_REF" != "no"; then
9 |
10 | AC_MSG_CHECKING([Check for supported PHP versions])
11 | PHP_REF_FOUND_VERSION=`${PHP_CONFIG} --version`
12 | PHP_REF_FOUND_VERNUM=`${PHP_CONFIG} --vernum`
13 |
14 | if test "$PHP_REF_FOUND_VERNUM" -lt "70200"; then
15 | AC_MSG_ERROR([not supported. PHP version >= 7.2 required (found $PHP_REF_FOUND_VERSION)])
16 | else
17 | AC_MSG_RESULT([supported ($PHP_REF_FOUND_VERSION)])
18 | fi
19 |
20 | echo "$PHP_VERSION_ID"
21 |
22 | if test -z "$TRAVIS" ; then
23 | type git &>/dev/null
24 |
25 | if test $? -eq 0 ; then
26 | git describe --abbrev=0 --tags &>/dev/null
27 |
28 | if test $? -eq 0 ; then
29 | AC_DEFINE_UNQUOTED([PHP_REF_VERSION], ["`git describe --abbrev=0 --tags`-`git rev-parse --abbrev-ref HEAD`-dev"], [git version])
30 | fi
31 |
32 | git rev-parse --short HEAD &>/dev/null
33 |
34 | if test $? -eq 0 ; then
35 | AC_DEFINE_UNQUOTED([PHP_REF_REVISION], ["`git rev-parse --short HEAD`"], [git revision])
36 | fi
37 | else
38 | AC_MSG_NOTICE([git not installed. Cannot obtain php-ref version tag. Install git.])
39 | fi
40 | fi
41 |
42 | PHP_NEW_EXTENSION(ref, [ \
43 | ref.c \
44 | php_ref_notifier_exception.c \
45 | php_ref_reference.c \
46 | php_ref_functions.c \
47 | ], $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
48 | fi
49 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-clone_extended.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - clone reference
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
32 |
33 | $wr2 = clone $wr;
34 |
35 | var_dump($wr2);
36 | $helper->line();
37 |
38 |
39 | ?>
40 | EOF
41 | --EXPECT--
42 | object(WeakTests\ExtendedWeakReference)#4 (3) {
43 | ["test":"WeakTests\ExtendedWeakReference":private]=>
44 | array(1) {
45 | [0]=>
46 | int(42)
47 | }
48 | ["referent":"Ref\AbstractReference":private]=>
49 | object(stdClass)#2 (0) {
50 | }
51 | ["notifier":"Ref\AbstractReference":private]=>
52 | object(Closure)#3 (1) {
53 | ["parameter"]=>
54 | array(1) {
55 | ["$ref"]=>
56 | string(10) ""
57 | }
58 | }
59 | }
60 |
61 | object(WeakTests\ExtendedWeakReference)#5 (3) {
62 | ["test":"WeakTests\ExtendedWeakReference":private]=>
63 | array(1) {
64 | [0]=>
65 | int(42)
66 | }
67 | ["referent":"Ref\AbstractReference":private]=>
68 | object(stdClass)#2 (0) {
69 | }
70 | ["notifier":"Ref\AbstractReference":private]=>
71 | object(Closure)#3 (1) {
72 | ["parameter"]=>
73 | array(1) {
74 | ["$ref"]=>
75 | string(10) ""
76 | }
77 | }
78 | }
79 |
80 | EOF
81 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-exception_in_multiple_callbacks.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - exception thrown in callback
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
42 | }
43 |
44 |
45 | $helper->line();
46 | ?>
47 | EOF
48 | --EXPECT--
49 | WeakTests\TrackingDtor's destructor called
50 | Callback #0 called
51 | Callback #1 called
52 | Callback #2 called
53 | Callback #3 called
54 | Callback #4 called
55 | Callback #5 called
56 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
57 | thrown:
58 | #0: Exception: Test exception from callback #1
59 | #1: Exception: Test exception from callback #3
60 |
61 | EOF
62 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-exception_in_multiple_callbacks.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - exception thrown in callback
3 | --SKIPIF--
4 |
5 | --FILE--
6 | ref_exception_export($e);
42 | }
43 |
44 |
45 | $helper->line();
46 | ?>
47 | EOF
48 | --EXPECT--
49 | Callback #0 called
50 | Callback #1 called
51 | Callback #2 called
52 | Callback #3 called
53 | Callback #4 called
54 | Callback #5 called
55 | WeakTests\TrackingDtor's destructor called
56 | Ref\NotifierException: One or more exceptions thrown during notifiers calling
57 | thrown:
58 | #0: Exception: Test exception from callback #1
59 | #1: Exception: Test exception from callback #3
60 |
61 | EOF
62 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-clone_extended.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - clone reference
3 | --SKIPIF--
4 |
5 | --FILE--
6 | line();
32 |
33 | $ref2 = clone $ref;
34 |
35 | var_dump($ref2);
36 | $helper->line();
37 |
38 |
39 | ?>
40 | EOF
41 | --EXPECT--
42 | object(WeakTests\ExtendedSoftReference)#4 (3) {
43 | ["test":"WeakTests\ExtendedSoftReference":private]=>
44 | array(1) {
45 | [0]=>
46 | int(42)
47 | }
48 | ["referent":"Ref\AbstractReference":private]=>
49 | object(stdClass)#2 (0) {
50 | }
51 | ["notifier":"Ref\AbstractReference":private]=>
52 | object(Closure)#3 (1) {
53 | ["parameter"]=>
54 | array(1) {
55 | ["$ref"]=>
56 | string(10) ""
57 | }
58 | }
59 | }
60 |
61 | object(WeakTests\ExtendedSoftReference)#5 (3) {
62 | ["test":"WeakTests\ExtendedSoftReference":private]=>
63 | array(1) {
64 | [0]=>
65 | int(42)
66 | }
67 | ["referent":"Ref\AbstractReference":private]=>
68 | object(stdClass)#2 (0) {
69 | }
70 | ["notifier":"Ref\AbstractReference":private]=>
71 | object(Closure)#3 (1) {
72 | ["parameter"]=>
73 | array(1) {
74 | ["$ref"]=>
75 | string(10) ""
76 | }
77 | }
78 | }
79 |
80 | EOF
81 |
--------------------------------------------------------------------------------
/tests/002-AbstractReference-basic.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\AbstractReference - dump representation, get() and valid() methods
3 | --SKIPIF--
4 |
5 | --FILE--
6 | exception_export($e);
19 | $helper->space();
20 | }
21 |
22 |
23 | $ref = new \WeakTests\TestAbstractReference($obj);
24 |
25 | $helper->header('When referent object alive');
26 | $helper->assert('Referent object dead', $ref->get() === $obj);
27 | $helper->assert('Referent object invalid', $ref->valid(), false);
28 | $helper->dump($ref);
29 | $helper->space();
30 |
31 | $obj = null;
32 |
33 |
34 | $helper->header('When referent object dead');
35 | $helper->assert('Referent object dead', $ref->get() === $obj);
36 | $helper->assert('Referent object invalid', $ref->valid(), false);
37 | $helper->dump($ref);
38 | $helper->line();
39 |
40 |
41 |
42 | ?>
43 | --EXPECT--
44 | Error: Cannot instantiate abstract class Ref\AbstractReference
45 |
46 |
47 | When referent object alive:
48 | ---------------------------
49 | Referent object dead: failed
50 | Referent object invalid: ok
51 | object(WeakTests\TestAbstractReference)#4 (2) refcount(3){
52 | ["referent":"Ref\AbstractReference":private]=>
53 | NULL
54 | ["notifier":"Ref\AbstractReference":private]=>
55 | NULL
56 | }
57 |
58 |
59 | When referent object dead:
60 | --------------------------
61 | Referent object dead: ok
62 | Referent object invalid: ok
63 | object(WeakTests\TestAbstractReference)#4 (2) refcount(3){
64 | ["referent":"Ref\AbstractReference":private]=>
65 | NULL
66 | ["notifier":"Ref\AbstractReference":private]=>
67 | NULL
68 | }
69 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-object-handle-reuse.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - reference should work for newly create tracked objects with same handles as previously tracked objects
3 | --SKIPIF--
4 |
5 | --FILE--
6 | storage[$hash]);
21 | });
22 |
23 | $value = new WeakReference($value, function () use ($hash) {
24 | unset($this->storage[$hash]);
25 | });
26 |
27 | $this->storage[$hash] = [$key, $value];
28 | }
29 | }
30 |
31 |
32 | $map = new Test();
33 |
34 | $key_1 = new stdClass();
35 | $value_1 = new stdClass();
36 |
37 | $key_2 = new stdClass();
38 | $value_2 = new stdClass();
39 |
40 | $map->put($key_1, $value_1, 'test_1');
41 | $map->put($key_2, $value_2, 'test_2');
42 |
43 | $helper->assert('count', 2, count($map->storage));
44 |
45 |
46 | $key_1 = null;
47 | $helper->assert('count', 1, count($map->storage));
48 |
49 |
50 | $value_2 = null;
51 | $helper->assert('count', 0, count($map->storage));
52 |
53 | $key_1 = new stdClass();
54 | $value_1 = new stdClass();
55 |
56 | $key_2 = new stdClass();
57 | $value_2 = new stdClass();
58 |
59 | $map->put($key_1, $value_1, 'test_1');
60 | $map->put($key_2, $value_2, 'test_2');
61 |
62 | $helper->assert('count', 2, count($map->storage));
63 |
64 | $key_1 = null;
65 | $helper->assert('count', 1, count($map->storage));
66 |
67 | $value_2 = null;
68 | $helper->assert('count', 0, count($map->storage));
69 |
70 |
71 | ?>
72 | --EXPECT--
73 | count: ok
74 | count: ok
75 | count: ok
76 | count: ok
77 | count: ok
78 | count: ok
79 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-closure.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - referencing closure
3 | --SKIPIF--
4 |
5 | --FILE--
6 | header('When referent object alive');
18 | $helper->assert('Referent object alive', $wr->get() === $obj);
19 | $helper->dump($wr);
20 | $helper->space();
21 |
22 | $obj = null;
23 |
24 | $helper->header('When referent object dead');
25 | $helper->assert('Referent object dead', $wr->get() === null);
26 |
27 | $helper->dump($wr);
28 |
29 | $helper->line();
30 | ?>
31 | EOF
32 | --EXPECT--
33 | When referent object alive:
34 | ---------------------------
35 | Referent object alive: ok
36 | object(Ref\WeakReference)#3 (2) refcount(3){
37 | ["referent":"Ref\AbstractReference":private]=>
38 | object(Closure)#2 (1) refcount(2){
39 | ["parameter"]=>
40 | array(1) refcount(1){
41 | ["$greeting"]=>
42 | string(10) "" refcount(1)
43 | }
44 | }
45 | ["notifier":"Ref\AbstractReference":private]=>
46 | object(Closure)#4 (1) refcount(2){
47 | ["parameter"]=>
48 | array(1) refcount(1){
49 | ["$reference"]=>
50 | string(10) "" refcount(1)
51 | }
52 | }
53 | }
54 |
55 |
56 | When referent object dead:
57 | --------------------------
58 | Referent object dead: ok
59 | object(Ref\WeakReference)#3 (2) refcount(3){
60 | ["referent":"Ref\AbstractReference":private]=>
61 | NULL
62 | ["notifier":"Ref\AbstractReference":private]=>
63 | object(Closure)#4 (1) refcount(2){
64 | ["parameter"]=>
65 | array(1) refcount(1){
66 | ["$reference"]=>
67 | string(10) "" refcount(1)
68 | }
69 | }
70 | }
71 |
72 | EOF
73 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-closure.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - referencing closure
3 | --SKIPIF--
4 |
5 | --FILE--
6 | header('When referent object alive');
18 | $helper->assert('Referent object alive', $sr->get() === $obj);
19 | $helper->dump($sr);
20 | $helper->space();
21 |
22 | $obj = null;
23 |
24 | $helper->header('When referent object dead');
25 | $helper->assert('Referent object dead', $sr->get() === null);
26 |
27 | $helper->dump($sr);
28 |
29 | $helper->line();
30 | ?>
31 | EOF
32 | --EXPECT--
33 | When referent object alive:
34 | ---------------------------
35 | Referent object alive: ok
36 | object(Ref\SoftReference)#3 (2) refcount(3){
37 | ["referent":"Ref\AbstractReference":private]=>
38 | object(Closure)#2 (1) refcount(2){
39 | ["parameter"]=>
40 | array(1) refcount(1){
41 | ["$greeting"]=>
42 | string(10) "" refcount(1)
43 | }
44 | }
45 | ["notifier":"Ref\AbstractReference":private]=>
46 | object(Closure)#4 (1) refcount(2){
47 | ["parameter"]=>
48 | array(1) refcount(1){
49 | ["$reference"]=>
50 | string(10) "" refcount(1)
51 | }
52 | }
53 | }
54 |
55 |
56 | When referent object dead:
57 | --------------------------
58 | Referent object dead: ok
59 | object(Ref\SoftReference)#3 (2) refcount(3){
60 | ["referent":"Ref\AbstractReference":private]=>
61 | NULL
62 | ["notifier":"Ref\AbstractReference":private]=>
63 | object(Closure)#4 (1) refcount(2){
64 | ["parameter"]=>
65 | array(1) refcount(1){
66 | ["$reference"]=>
67 | string(10) "" refcount(1)
68 | }
69 | }
70 | }
71 |
72 | EOF
73 |
--------------------------------------------------------------------------------
/provision/nginx/default:
--------------------------------------------------------------------------------
1 | # You may add here your
2 | # server {
3 | # ...
4 | # }
5 | # statements for each of your virtual hosts to this file
6 |
7 | ##
8 | # You should look at the following URL's in order to grasp a solid understanding
9 | # of Nginx configuration files in order to fully unleash the power of Nginx.
10 | # http://wiki.nginx.org/Pitfalls
11 | # http://wiki.nginx.org/QuickStart
12 | # http://wiki.nginx.org/Configuration
13 | #
14 | # Generally, you will want to move this file somewhere, and start with a clean
15 | # file but keep this around for reference. Or just disable in sites-enabled.
16 | #
17 | # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
18 | ##
19 |
20 | server {
21 | listen 80 default_server;
22 | listen [::]:80 default_server ipv6only=on;
23 |
24 | root /var/www/html;
25 | index index.php index-nginx.html;
26 |
27 | # Make site accessible from http://localhost/
28 | server_name localhost;
29 |
30 | location / {
31 | # First attempt to serve request as file, then
32 | # as directory, then fall back to displaying a 404.
33 | try_files $uri $uri/ =404;
34 | # Uncomment to enable naxsi on this location
35 | # include /etc/nginx/naxsi.rules
36 | }
37 |
38 | # Only for nginx-naxsi used with nginx-naxsi-ui : process denied requests
39 | #location /RequestDenied {
40 | # proxy_pass http://127.0.0.1:8080;
41 | #}
42 |
43 | #error_page 404 /404.html;
44 |
45 | # redirect server error pages to the static page /50x.html
46 | #
47 | error_page 500 502 503 504 /50x.html;
48 | location = /50x.html {
49 | root /usr/share/nginx/html;
50 | }
51 |
52 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
53 | #
54 | location ~ \.php$ {
55 | include fastcgi_params;
56 | #fastcgi_split_path_info ^(.+\.php)(/.+)$;
57 | # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
58 |
59 | # With php5-cgi alone:
60 | fastcgi_pass 127.0.0.1:9000;
61 | # With php5-fpm:
62 | #fastcgi_pass unix:/var/run/php5-fpm.sock;
63 | fastcgi_index index.php;
64 | fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
65 | }
66 | }
--------------------------------------------------------------------------------
/php_ref_reference.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the pinepain/php-ref PHP extension.
3 | *
4 | * Copyright (c) 2016-2018 Bogdan Padalko
5 | *
6 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
7 | *
8 | * For the full copyright and license information, please view the
9 | * LICENSE file that was distributed with this source or visit
10 | * http://opensource.org/licenses/MIT
11 | */
12 |
13 | #ifndef PHP_REF_REFERENCE_H
14 | #define PHP_REF_REFERENCE_H
15 |
16 | #include "php.h"
17 |
18 | #ifdef ZTS
19 | #include "TSRM.h"
20 | #endif
21 |
22 | extern zend_class_entry *php_ref_abstract_reference_class_entry;
23 | extern zend_class_entry *php_ref_soft_reference_class_entry;
24 | extern zend_class_entry *php_ref_weak_reference_class_entry;
25 |
26 |
27 | typedef struct _php_ref_referent_t php_ref_referent_t;
28 | typedef struct _php_ref_reference_t php_ref_reference_t;
29 |
30 | typedef void (*php_ref_register)(php_ref_reference_t *reference, php_ref_referent_t *referent);
31 | typedef void (*php_ref_unregister)(php_ref_reference_t *reference);
32 |
33 | extern php_ref_reference_t *php_ref_reference_fetch_object(zend_object *obj);
34 | extern php_ref_referent_t *php_ref_referent_find_ptr(zend_ulong h);
35 | extern void php_ref_globals_referents_ht_dtor(zval *zv);
36 |
37 |
38 | #define PHP_REF_REFERENCE_FETCH(zv) php_ref_reference_fetch_object(Z_OBJ_P(zv))
39 | #define PHP_REF_REFERENCE_FETCH_INTO(pzval, into) php_ref_reference_t *(into) = PHP_REF_REFERENCE_FETCH((pzval));
40 |
41 | struct _php_ref_referent_t {
42 | zval this_ptr;
43 | uint32_t handle;
44 |
45 | zend_object_handlers custom_handlers;
46 | const zend_object_handlers *original_handlers;
47 |
48 | HashTable soft_references;
49 | HashTable weak_references;
50 |
51 | uint32_t tracked;
52 | };
53 |
54 | struct _php_ref_reference_t {
55 | php_ref_referent_t *referent;
56 |
57 | zval notifier;
58 |
59 | php_ref_register register_reference;
60 | php_ref_unregister unregister_reference;
61 |
62 | zval this_ptr;
63 | zend_object std;
64 | };
65 |
66 |
67 | PHP_MINIT_FUNCTION(php_ref_reference);
68 |
69 |
70 | #endif /* PHP_REF_REFERENCE_H */
71 |
--------------------------------------------------------------------------------
/tests/003-functions-weakrefcounted_after_all_refs_died.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\functions - test weakrefcount() functions after all references death
3 | --SKIPIF--
4 |
5 | --FILE--
6 | header('Test before any reference created');
26 | $helper->dump_annotated('weakrefcounted($obj)', weakrefcounted($obj));
27 | $helper->dump_annotated('weakrefcount($obj)', weakrefcount($obj));
28 | $helper->dump_annotated('weakrefs($obj)', weakrefs($obj));
29 | $helper->line();
30 |
31 |
32 | $ref = new WeakReference($obj);
33 |
34 | $helper->header('Test when reference created');
35 | $helper->dump_annotated('weakrefcounted($obj)', weakrefcounted($obj));
36 | $helper->dump_annotated('weakrefcount($obj)', weakrefcount($obj));
37 | $helper->dump_annotated('weakrefs($obj)', weakrefs($obj));
38 | $helper->line();
39 |
40 | $ref = null;
41 |
42 | $helper->header('Test when reference destroyed');
43 | $helper->dump_annotated('weakrefcounted($obj)', weakrefcounted($obj));
44 | $helper->dump_annotated('weakrefcount($obj)', weakrefcount($obj));
45 | $helper->dump_annotated('weakrefs($obj)', weakrefs($obj));
46 | $helper->line();
47 |
48 | ?>
49 | --EXPECT--
50 | Test before any reference created:
51 | ----------------------------------
52 | weakrefcounted($obj): bool(false)
53 | weakrefcount($obj): int(0)
54 | weakrefs($obj): array(0) refcount(3){
55 | }
56 |
57 | Test when reference created:
58 | ----------------------------
59 | weakrefcounted($obj): bool(true)
60 | weakrefcount($obj): int(1)
61 | weakrefs($obj): array(1) refcount(3){
62 | [0]=>
63 | object(Ref\WeakReference)#3 (2) refcount(2){
64 | ["referent":"Ref\AbstractReference":private]=>
65 | object(stdClass)#2 (0) refcount(2){
66 | }
67 | ["notifier":"Ref\AbstractReference":private]=>
68 | NULL
69 | }
70 | }
71 |
72 | Test when reference destroyed:
73 | ------------------------------
74 | weakrefcounted($obj): bool(false)
75 | weakrefcount($obj): int(0)
76 | weakrefs($obj): array(0) refcount(3){
77 | }
78 |
--------------------------------------------------------------------------------
/tests/002-AbstractReference-clone.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\AbstractReference - clone reference
3 | --SKIPIF--
4 |
5 | --FILE--
6 | export_annotated('weakrefcount($obj)', weakrefcount($obj));
26 | $helper->export_annotated('softrefcount($obj)', softrefcount($obj));
27 | var_dump($ar);
28 | $helper->line();
29 |
30 | $ar2 = clone $ar;
31 |
32 | $helper->assert('Cloned abstract reference matches original', $ar == $ar2);
33 | $helper->assert('Cloned abstract reference does not match original abstract reference strictly', $ar !== $ar2);
34 | $helper->line();
35 |
36 | $helper->export_annotated('weakrefcount($obj)', weakrefcount($obj));
37 | $helper->export_annotated('softrefcount($obj)', softrefcount($obj));
38 | var_dump($ar2);
39 | $helper->line();
40 |
41 | $helper->assert('Abstract references reported with cloned reference', weakrefs($obj), [$ar, $ar2]);
42 | $helper->line();
43 |
44 | $obj = null;
45 | $helper->line();
46 |
47 | $helper->assert('Cloned abstract reference matches original', $ar == $ar2);
48 | $helper->assert('Cloned abstract reference does not match original weak reference strictly', $ar !== $ar2);
49 | $helper->line();
50 |
51 |
52 | ?>
53 | EOF
54 | --EXPECT--
55 | weakrefcount($obj): integer: 0
56 | softrefcount($obj): integer: 0
57 | object(WeakTests\TestAbstractReference)#4 (2) {
58 | ["referent":"Ref\AbstractReference":private]=>
59 | NULL
60 | ["notifier":"Ref\AbstractReference":private]=>
61 | object(Closure)#3 (0) {
62 | }
63 | }
64 |
65 | Cloned abstract reference matches original: ok
66 | Cloned abstract reference does not match original abstract reference strictly: ok
67 |
68 | weakrefcount($obj): integer: 0
69 | softrefcount($obj): integer: 0
70 | object(WeakTests\TestAbstractReference)#5 (2) {
71 | ["referent":"Ref\AbstractReference":private]=>
72 | NULL
73 | ["notifier":"Ref\AbstractReference":private]=>
74 | object(Closure)#3 (0) {
75 | }
76 | }
77 |
78 | Abstract references reported with cloned reference: failed
79 |
80 |
81 | Cloned abstract reference matches original: ok
82 | Cloned abstract reference does not match original weak reference strictly: ok
83 |
84 | EOF
85 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-notifier_change.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - changing notifier
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier is null by default', $wr->notifier(), null);
23 | $helper->assert('Notifier was null', $wr->notifier($callback_notifier_1), NULL);
24 | $helper->assert('Notifier is callback', $wr->notifier(), $callback_notifier_1);
25 |
26 | $obj = null;
27 | $helper->line();
28 |
29 |
30 | $obj = new stdClass();
31 | $wr = new Ref\WeakReference($obj, $callback_notifier_1);
32 |
33 | $helper->assert('Notifier is callback by default', $wr->notifier(), $callback_notifier_1);
34 | $helper->assert('Notifier was callback', $wr->notifier($callback_notifier_2), $callback_notifier_1);
35 | $helper->assert('Notifier is callback', $wr->notifier(), $callback_notifier_2);
36 |
37 | $obj = null;
38 | $helper->line();
39 |
40 | $obj = new stdClass();
41 | $wr = new Ref\WeakReference($obj, $callback_notifier_1);
42 |
43 | $helper->assert('Notifier is callback by default', $wr->notifier(), $callback_notifier_1);
44 | $helper->assert('Notifier was callback', $wr->notifier($callback_notifier_2), $callback_notifier_1);
45 | $helper->assert('Notifier is callback', $wr->notifier(), $callback_notifier_2);
46 |
47 | $obj = null;
48 | $helper->line();
49 |
50 |
51 | $notifier = 'var_dump';
52 | $wr->notifier($notifier);
53 |
54 | try {
55 | $wr->notifier('nonexistent');
56 | } catch (Error $e) {
57 | $helper->exception_export($e);
58 | }
59 |
60 | $helper->assert('Notifier stays the same', $wr->notifier(), $notifier);
61 | $helper->line();
62 |
63 | ?>
64 | EOF
65 | --EXPECT--
66 | Notifier is null by default: ok
67 | Notifier was null: ok
68 | Notifier is callback: ok
69 | Callback notifier 1
70 |
71 | Notifier is callback by default: ok
72 | Notifier was callback: ok
73 | Notifier is callback: ok
74 | Callback notifier 2
75 |
76 | Notifier is callback by default: ok
77 | Notifier was callback: ok
78 | Notifier is callback: ok
79 | Callback notifier 2
80 |
81 | TypeError: Argument 1 passed to Ref\AbstractReference::notifier() must be callable or null, string given
82 | Notifier stays the same: ok
83 |
84 | EOF
85 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notifier_change.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - changing notifier
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier is null by default', $sr->notifier(), null);
23 | $helper->assert('Notifier was null', $sr->notifier($callback_notifier_1), NULL);
24 | $helper->assert('Notifier is callback', $sr->notifier(), $callback_notifier_1);
25 |
26 | $obj = null;
27 | $helper->line();
28 |
29 |
30 | $obj = new stdClass();
31 | $sr = new Ref\SoftReference($obj, $callback_notifier_1);
32 |
33 | $helper->assert('Notifier is callback by default', $sr->notifier(), $callback_notifier_1);
34 | $helper->assert('Notifier was callback', $sr->notifier($callback_notifier_2), $callback_notifier_1);
35 | $helper->assert('Notifier is callback', $sr->notifier(), $callback_notifier_2);
36 |
37 | $obj = null;
38 | $helper->line();
39 |
40 | $obj = new stdClass();
41 | $sr = new Ref\SoftReference($obj, $callback_notifier_1);
42 |
43 | $helper->assert('Notifier is callback by default', $sr->notifier(), $callback_notifier_1);
44 | $helper->assert('Notifier was callback', $sr->notifier($callback_notifier_2), $callback_notifier_1);
45 | $helper->assert('Notifier is callback', $sr->notifier(), $callback_notifier_2);
46 |
47 | $obj = null;
48 | $helper->line();
49 |
50 |
51 | $notifier = 'var_dump';
52 | $sr->notifier($notifier);
53 |
54 | try {
55 | $sr->notifier('nonexistent');
56 | } catch (Error $e) {
57 | $helper->exception_export($e);
58 | }
59 |
60 | $helper->assert('Notifier stays the same', $sr->notifier(), $notifier);
61 | $helper->line();
62 |
63 | ?>
64 | EOF
65 | --EXPECT--
66 | Notifier is null by default: ok
67 | Notifier was null: ok
68 | Notifier is callback: ok
69 | Callback notifier 1
70 |
71 | Notifier is callback by default: ok
72 | Notifier was callback: ok
73 | Notifier is callback: ok
74 | Callback notifier 2
75 |
76 | Notifier is callback by default: ok
77 | Notifier was callback: ok
78 | Notifier is callback: ok
79 | Callback notifier 2
80 |
81 | TypeError: Argument 1 passed to Ref\AbstractReference::notifier() must be callable or null, string given
82 | Notifier stays the same: ok
83 |
84 | EOF
85 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-spl_object_storage_hash_consistent.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - SplObjectStorage::getHash() still consistent before and after wrapping
3 | --SKIPIF--
4 |
5 | --FILE--
6 | getHash($obj);
16 |
17 | $wr = new Ref\WeakReference($obj);
18 |
19 | $current_hash = $s->getHash($obj);
20 |
21 | $helper->assert('Wrapped object hash matches origin one', $original_hash == $current_hash);
22 |
23 |
24 | $wr2 = new Ref\WeakReference($obj);
25 |
26 | $double_hash = $s->getHash($obj);
27 | $helper->assert('Repeatedly wrapped object hash does not changes', $current_hash == $double_hash);
28 |
29 | $wr = null;
30 |
31 | $again_hash = $s->getHash($obj);
32 | $helper->assert('Repeatedly wrapped object hash does not changes after some reference death', $current_hash == $again_hash);
33 |
34 | $wr2 = null;
35 |
36 | $nullified_hash = $s->getHash($obj);
37 | $helper->assert('Wrapped object hash still not changed even after all references died', $current_hash == $original_hash);
38 | $helper->assert('Wrapped object hash still the same even after all references died', $current_hash == $nullified_hash);
39 |
40 | $helper->line();
41 |
42 | $s = new SplObjectStorage();
43 | $obj = new stdClass();
44 | $original_hash = spl_object_hash($obj);
45 | $s->attach($obj);
46 | $current_hash = spl_object_hash($obj);
47 | $helper->assert('Stored in SplObjectStorage object hash matches origin one', $original_hash == $current_hash);
48 |
49 | $s = new SplObjectStorage();
50 | $obj = new stdClass();
51 | $original_hash = spl_object_hash($obj);
52 | $wr = new Ref\WeakReference($obj);
53 | $s->attach($wr);
54 | $current_hash = spl_object_hash($obj);
55 | $helper->assert('Stored in SplObjectStorage weak-referenced object hash matches origin one', $original_hash == $current_hash);
56 |
57 | $helper->line();
58 |
59 | ?>
60 | EOF
61 | --EXPECT--
62 | Wrapped object hash matches origin one: ok
63 | Repeatedly wrapped object hash does not changes: ok
64 | Repeatedly wrapped object hash does not changes after some reference death: ok
65 | Wrapped object hash still not changed even after all references died: ok
66 | Wrapped object hash still the same even after all references died: ok
67 |
68 | Stored in SplObjectStorage object hash matches origin one: ok
69 | Stored in SplObjectStorage weak-referenced object hash matches origin one: ok
70 |
71 | EOF
72 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-spl_object_storage_hash_consistent.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - SplObjectStorage::getHash() still consistent before and after wrapping
3 | --SKIPIF--
4 |
5 | --FILE--
6 | getHash($obj);
16 |
17 | $sr = new Ref\SoftReference($obj);
18 |
19 | $current_hash = $s->getHash($obj);
20 |
21 | $helper->assert('Wrapped object hash matches origin one', $original_hash == $current_hash);
22 |
23 |
24 | $sr2 = new Ref\SoftReference($obj);
25 |
26 | $double_hash = $s->getHash($obj);
27 | $helper->assert('Repeatedly wrapped object hash does not changes', $current_hash == $double_hash);
28 |
29 | $sr = null;
30 |
31 | $again_hash = $s->getHash($obj);
32 | $helper->assert('Repeatedly wrapped object hash does not changes after some reference death', $current_hash == $again_hash);
33 |
34 | $sr2 = null;
35 |
36 | $nullified_hash = $s->getHash($obj);
37 | $helper->assert('Wrapped object hash still not changed even after all references died', $current_hash == $original_hash);
38 | $helper->assert('Wrapped object hash still the same even after all references died', $current_hash == $nullified_hash);
39 |
40 | $helper->line();
41 |
42 | $s = new SplObjectStorage();
43 | $obj = new stdClass();
44 | $original_hash = spl_object_hash($obj);
45 | $s->attach($obj);
46 | $current_hash = spl_object_hash($obj);
47 | $helper->assert('Stored in SplObjectStorage object hash matches origin one', $original_hash == $current_hash);
48 |
49 | $s = new SplObjectStorage();
50 | $obj = new stdClass();
51 | $original_hash = spl_object_hash($obj);
52 | $sr = new Ref\SoftReference($obj);
53 | $s->attach($sr);
54 | $current_hash = spl_object_hash($obj);
55 | $helper->assert('Stored in SplObjectStorage soft-referenced object hash matches origin one', $original_hash == $current_hash);
56 |
57 | $helper->line();
58 |
59 | ?>
60 | EOF
61 | --EXPECT--
62 | Wrapped object hash matches origin one: ok
63 | Repeatedly wrapped object hash does not changes: ok
64 | Repeatedly wrapped object hash does not changes after some reference death: ok
65 | Wrapped object hash still not changed even after all references died: ok
66 | Wrapped object hash still the same even after all references died: ok
67 |
68 | Stored in SplObjectStorage object hash matches origin one: ok
69 | Stored in SplObjectStorage soft-referenced object hash matches origin one: ok
70 |
71 | EOF
72 |
--------------------------------------------------------------------------------
/stubs/src/functions.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
9 | *
10 | * For the full copyright and license information, please view the
11 | * LICENSE file that was distributed with this source or visit
12 | * http://opensource.org/licenses/MIT
13 | */
14 |
15 |
16 | namespace Ref;
17 |
18 | /**
19 | * Check whether value is refcounted
20 | *
21 | * @param mixed $value
22 | *
23 | * @return bool
24 | */
25 | function refcounted(mixed $value): bool
26 | {
27 | }
28 |
29 | /**
30 | * Get real object references count (not counting value reference passed as a function argument)
31 | *
32 | * @param object $object
33 | *
34 | * @return int
35 | */
36 | function refcount(object $object): int
37 | {
38 | }
39 |
40 | /**
41 | * Check whether object has soft references
42 | *
43 | * @param object $value
44 | *
45 | * @return bool
46 | */
47 | function softrefcounted(object $value): bool
48 | {
49 | }
50 |
51 | /**
52 | * Get object's soft references count
53 | *
54 | * @param object $value
55 | *
56 | * @return int
57 | */
58 | function softrefcount(object $value): int
59 | {
60 | }
61 |
62 | /**
63 | * Get object's soft references
64 | *
65 | * @param object $value
66 | *
67 | * @return mixed
68 | */
69 | function softrefs(object $value): array
70 | {
71 | }
72 |
73 | /**
74 | * Check whether object has weak references
75 | *
76 | * @param object $value
77 | *
78 | * @return bool
79 | */
80 | function weakrefcounted(object $value): bool
81 | {
82 | }
83 |
84 | /**
85 | * Get object's weak references count
86 | *
87 | * @param object $value
88 | *
89 | * @return int
90 | */
91 | function weakrefcount(object $value): int
92 | {
93 | }
94 |
95 | /**
96 | * Get object's weak references
97 | *
98 | * @param object $value
99 | *
100 | * @return mixed
101 | */
102 | function weakrefs(object $value): array
103 | {
104 | }
105 |
106 | /**
107 | * Get object's handle id
108 | *
109 | * @param object $value
110 | *
111 | * @return int
112 | */
113 | function object_handle(object $value): int
114 | {
115 | }
116 |
117 | /**
118 | * Check whether object's destructor was called
119 | *
120 | * @param object $value
121 | *
122 | * @return bool
123 | */
124 | function is_obj_destructor_called(object $value): bool
125 | {
126 | }
127 |
--------------------------------------------------------------------------------
/stubs/src/AbstractReference.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
9 | *
10 | * For the full copyright and license information, please view the
11 | * LICENSE file that was distributed with this source or visit
12 | * http://opensource.org/licenses/MIT
13 | */
14 |
15 | namespace Ref;
16 |
17 |
18 | /**
19 | * Class AbstractReference
20 | *
21 | * Abstract base class for reference objects. This class defines the operations common to all reference objects.
22 | * Because of reference objects implementation details which depends on how GC in PHP works, this class may not be
23 | * subclassed directly.
24 | */
25 | abstract class AbstractReference
26 | {
27 | /**
28 | * @param object $referent Referent object
29 | * @param callable|null $notify Optional notifier to signal when referent object destroyed.
30 | *
31 | * If notifier is callback, it will be called with a current reference object as a first argument.
32 | *
33 | * For SoftReference, notifiers are called before object will (or will not) be destructed. If referent object
34 | * prevented from being destroyed (regular reference to it created during SoftReference notifiers calling), original
35 | * object's destructor will not be called and next time referent object refcount will reach 0 it will be a subject of
36 | * full destructing cycle again. For WeakReference, referent object will be already destroyed at the time of
37 | * notifiers calling.
38 | */
39 | public function __construct(object $referent, callable $notify = null)
40 | {
41 | }
42 |
43 | /**
44 | * Get referent object
45 | *
46 | * @return object|null
47 | */
48 | public function get()
49 | {
50 | }
51 |
52 | /**
53 | * Whether referent object exists
54 | *
55 | * @return bool
56 | */
57 | public function valid(): bool
58 | {
59 | }
60 |
61 | /**
62 | * Get notifier
63 | *
64 | * @param callable|null $notify Notifier to replace existent notifier with. Same as in constructor.
65 | *
66 | * If any value provided, any existent notifier will be replaced and returned.
67 | *
68 | * @return callable|null Current notifier or the old one when replacing it with provided value.
69 | */
70 | public function notifier(callable $notify = null): ?callable
71 | {
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/tests/.stubs.php:
--------------------------------------------------------------------------------
1 | storage[$offset]);
35 | }
36 |
37 | public function offsetGet($offset)
38 | {
39 | echo static::class, '::offsetGet called', PHP_EOL;
40 | return $this->storage[$offset];
41 | }
42 |
43 | public function offsetSet($offset, $value)
44 | {
45 | echo static::class, '::offsetSet called', PHP_EOL;
46 | $this->storage[$offset] = $value;
47 | }
48 |
49 | public function offsetUnset($offset)
50 | {
51 | echo static::class, '::offsetUnset called', PHP_EOL;
52 | unset($this->storage[$offset]);
53 | }
54 | }
55 |
56 | class TestArrayAccessCountable extends TestArrayAccess implements \Countable {
57 |
58 | public function count()
59 | {
60 | return count($this->storage);
61 | }
62 | }
63 |
64 | class TestProperties {
65 | public $public = 'public';
66 | public $public_for_test = 'public for test';
67 | public $public_for_proxy = 'public for proxy';
68 |
69 | protected $protected = 'protected';
70 |
71 | private $private = 'private';
72 | }
73 |
74 | class ExtendedWeakReference extends \Ref\WeakReference {
75 | /**
76 | * @var
77 | */
78 | private $test = [];
79 |
80 | public function __construct($referent, $notify, $test)
81 | {
82 | parent::__construct($referent, $notify);
83 | $this->test = $test;
84 | }
85 | }
86 |
87 | class ExtendedSoftReference extends \Ref\SoftReference {
88 | /**
89 | * @var
90 | */
91 | private $test = [];
92 |
93 | public function __construct($referent, $notify, $test)
94 | {
95 | parent::__construct($referent, $notify);
96 | $this->test = $test;
97 | }
98 | }
99 |
100 | class TestAbstractReference extends \Ref\AbstractReference
101 | {
102 | }
103 |
--------------------------------------------------------------------------------
/ref.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the pinepain/php-ref PHP extension.
3 | *
4 | * Copyright (c) 2016-2018 Bogdan Padalko
5 | *
6 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
7 | *
8 | * For the full copyright and license information, please view the
9 | * LICENSE file that was distributed with this source or visit
10 | * http://opensource.org/licenses/MIT
11 | */
12 |
13 | #ifdef HAVE_CONFIG_H
14 | #include "config.h"
15 | #endif
16 |
17 | #include "php_ref_functions.h"
18 | #include "php_ref_reference.h"
19 | #include "php_ref_notifier_exception.h"
20 | #include "php_ref.h"
21 |
22 | #include "ext/standard/info.h"
23 |
24 | ZEND_DECLARE_MODULE_GLOBALS(ref)
25 |
26 | /* True global resources - no need for thread safety here */
27 | static int le_ref;
28 |
29 | PHP_MINIT_FUNCTION(ref)
30 | {
31 | PHP_MINIT(php_ref_notifier_exception)(INIT_FUNC_ARGS_PASSTHRU);
32 | PHP_MINIT(php_ref_reference)(INIT_FUNC_ARGS_PASSTHRU);
33 |
34 | return SUCCESS;
35 | }
36 |
37 | PHP_MSHUTDOWN_FUNCTION(ref)
38 | {
39 | return SUCCESS;
40 | }
41 |
42 | PHP_RINIT_FUNCTION(ref)
43 | {
44 | #if defined(COMPILE_DL_REF) && defined(ZTS)
45 | ZEND_TSRMLS_CACHE_UPDATE();
46 | #endif
47 | return SUCCESS;
48 | }
49 |
50 | PHP_RSHUTDOWN_FUNCTION(ref)
51 | {
52 | if (NULL != PHP_REF_G(referents)) {
53 | zend_hash_destroy(PHP_REF_G(referents));
54 | FREE_HASHTABLE(PHP_REF_G(referents));
55 | PHP_REF_G(referents) = NULL;
56 | }
57 |
58 | return SUCCESS;
59 | }
60 |
61 |
62 | PHP_MINFO_FUNCTION(ref)
63 | {
64 | php_info_print_table_start();
65 | php_info_print_table_header(2, "Ref support", "enabled");
66 | php_info_print_table_row(2, "Version", PHP_REF_VERSION);
67 | php_info_print_table_row(2, "Revision", PHP_REF_REVISION);
68 | php_info_print_table_row(2, "Compiled", __DATE__ " @ " __TIME__);
69 |
70 | php_info_print_table_end();
71 | }
72 |
73 | static PHP_GINIT_FUNCTION(ref)
74 | {
75 | ref_globals->referents = NULL;
76 | }
77 |
78 | zend_module_entry php_ref_module_entry = {
79 | STANDARD_MODULE_HEADER,
80 | "ref",
81 | php_ref_functions,
82 | PHP_MINIT(ref),
83 | PHP_MSHUTDOWN(ref),
84 | PHP_RINIT(ref),
85 | PHP_RSHUTDOWN(ref),
86 | PHP_MINFO(ref),
87 | PHP_REF_VERSION,
88 | PHP_MODULE_GLOBALS(ref),
89 | PHP_GINIT(ref),
90 | NULL,
91 | NULL,
92 | STANDARD_MODULE_PROPERTIES_EX
93 | };
94 |
95 | #ifdef COMPILE_DL_REF
96 | #ifdef ZTS
97 | ZEND_TSRMLS_CACHE_DEFINE();
98 | #endif
99 | ZEND_GET_MODULE(php_ref)
100 | #endif
101 |
--------------------------------------------------------------------------------
/tests/001-verify-methods-signature.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Check whether methods signature is valid
3 | --SKIPIF--
4 |
5 | --FILE--
6 | getClasses();
10 |
11 |
12 | class Verifier
13 | {
14 | private $invalid = [];
15 |
16 | public function verifyClass(ReflectionClass $class)
17 | {
18 | foreach ($class->getMethods() as $m) {
19 | $this->verifyMethod($m);
20 | }
21 | }
22 |
23 | public function verifyMethod(ReflectionMethod $method)
24 | {
25 | foreach ($method->getParameters() as $p) {
26 | $this->verifyParameter($p);
27 | }
28 |
29 | if ($method->getReturnType()) {
30 | $type = $method->getReturnType();
31 |
32 | if (!$type || $type->isBuiltin()) {
33 | return;
34 | }
35 |
36 | if(!class_exists($type) && !interface_exists($type)) {
37 | $method_name = $method->getDeclaringClass()->getName() . '::' . $method->getName();
38 | $shortcut = $method_name . '/return type';
39 | if (isset($this->invalid[$shortcut])) {
40 | return;
41 | }
42 |
43 | $this->invalid[$shortcut] = true;
44 |
45 | echo "{$method_name}() method's return type is invalid ($type)", PHP_EOL;
46 | }
47 | }
48 |
49 | }
50 |
51 | protected function verifyReturnType(ReflectionType $rt) {
52 |
53 | }
54 |
55 | public function verifyParameter(ReflectionParameter $parameter)
56 | {
57 | $type = $parameter->getType();
58 |
59 | if (!$type || $type->isBuiltin()) {
60 | return;
61 | }
62 |
63 | if (!class_exists($type) && !interface_exists($type)) {
64 | $method_name = $parameter->getDeclaringClass()->getName() . '::' . $parameter->getDeclaringFunction()->getName();
65 | $param_name = $parameter->getName();
66 |
67 | $shortcut = $method_name . '/' . $param_name;
68 |
69 | if (isset($this->invalid[$shortcut])) {
70 | return;
71 | }
72 |
73 | $this->invalid[$shortcut] = true;
74 |
75 | echo "{$method_name}() method's parameter {$parameter->getName()} has invalid type ($type)", PHP_EOL;
76 | }
77 | }
78 |
79 | public function isValid()
80 | {
81 | return empty($this->invalid);
82 | }
83 | }
84 |
85 | $v = new Verifier();
86 |
87 |
88 | foreach ($classes as $c) {
89 | $v->verifyClass($c);
90 | }
91 |
92 | if ($v->isValid()) {
93 | echo 'All method parameters are valid', PHP_EOL;
94 | }
95 |
96 | ?>
97 | --EXPECT--
98 | All method parameters are valid
99 |
--------------------------------------------------------------------------------
/provision/provision.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo Provisioning...
4 | sudo apt-get update
5 | sudo apt-get -y autoremove
6 |
7 | # Make sure these tools installed
8 | sudo DEBIAN_FRONTEND=noninteractive apt-get install -y git htop curl tshark pkgconf
9 | # Add PPA with fresh PHP 7:
10 | sudo add-apt-repository -u -y ppa:ondrej/php
11 |
12 | # Install available php from packages
13 | sudo apt-get install -y php7.2 php7.2-dev php7.2-fpm
14 |
15 | # Configure php-fpm
16 | sudo cp ~/php-ref/provision/php/www.conf /etc/php/7.2/fpm/pool.d/www.conf
17 | sudo service php7.2-fpm restart
18 |
19 | # Fix php executable detection with PHP7 (https://github.com/oerdnj/deb.sury.org/issues/142)
20 | sudo sed -i -e 's/^php_cli_binary=NONE$/php_cli_binary="\/usr\/bin\/php"/g' /usr/bin/php-config
21 |
22 | # Install phpbrew to manage php versions
23 | curl -L -O -s https://github.com/phpbrew/phpbrew/raw/master/phpbrew
24 | chmod +x phpbrew
25 | sudo mv phpbrew /usr/bin/phpbrew
26 | phpbrew init
27 |
28 | cp ~/php-ref/provision/.bashrc ~/.bashrc
29 |
30 | sudo mkdir -p /var/www/html/
31 | sudo chown -R vagrant:vagrant /var/www
32 |
33 | # Requirements to build php from sources, uncomment if you decide to do so
34 | sudo apt-get install -y \
35 | libxml2-dev \
36 | libcurl4-openssl-dev \
37 | libjpeg-dev \
38 | libpng-dev \
39 | libxpm-dev \
40 | libmcrypt-dev \
41 | libmysqlclient-dev \
42 | libpq-dev \
43 | libicu-dev \
44 | libfreetype6-dev \
45 | libldap2-dev \
46 | libxslt-dev \
47 | libbz2-dev \
48 | libreadline-dev \
49 | autoconf \
50 | libtool \
51 | pkg-config
52 |
53 | # Valgrind for investigating and plumbing memory-related problems
54 | sudo apt-get install valgrind
55 |
56 | # Benchmarking...
57 | sudo apt-get install -y apache2-utils
58 | # For Apache-based installation
59 | sudo apt-get install -y apache2 libapache2-mod-php
60 |
61 | # Move Apache to port 8080
62 | sudo cp ~/php-ref/provision/apache/000-default.conf /etc/apache2/sites-available/000-default.conf
63 | sudo cp ~/php-ref/provision/apache/ports.conf /etc/apache2/ports.conf
64 | sudo service apache2 restart
65 |
66 | sudo cp -f /var/www/html/index.html /var/www/html/index-apache.html
67 |
68 | sudo bash -c "echo ' /var/www/html/index.php"
69 |
70 | # For Nginx-based installation
71 | sudo apt-get install -y nginx
72 | sudo cp ~/php-ref/provision/nginx/default /etc/nginx/sites-available/default
73 | sudo service nginx restart
74 | sudo cp -f /usr/share/nginx/html/index.html /var/www/html/index-nginx.html
75 |
76 |
77 | # Do it manually when you need it,
78 | #cd ~/php-ref
79 | #phpize --clean && phpize && ./configure && sudo make install
80 | #sudo cp ~/php-ref/provision/php/ref.ini /etc/php/mods-available/
81 | #sudo phpenmod -v ALL ref
82 | #sudo service php7.2-fpm restart
83 |
84 | # For debugging segfault when extension fails in php-fpm mode:
85 | #sudo sh -c "echo '/home/vagrant/php-ref/coredump-%e.%p' > /proc/sys/kernel/core_pattern"
86 |
87 | # To test with typical dev configuration - with xdebug:
88 | #sudo apt-get install -y php-xdebug
89 |
90 | # Cleanup unused stuff
91 | sudo apt-get autoremove -y
92 |
93 | # This is for the future
94 | # At this point it is good idea to do `phpbrew install 7.2` (or other version you want to test extension with)
95 | # and `phpbrew ext install ~/php-ref/`
96 |
97 | date > /home/vagrant/vagrant_provisioned_at
98 |
--------------------------------------------------------------------------------
/tests/003-functions-soft.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\functions - test functions
3 | --SKIPIF--
4 |
5 | --FILE--
6 | header('Test Ref\softrefcounted');
39 | $helper->export_annotated('softrefcounted($obj1)', softrefcounted($obj1));
40 | $helper->export_annotated('softrefcounted($obj2)', softrefcounted($obj2));
41 | $helper->export_annotated('softrefcounted($obj3)', softrefcounted($obj3));
42 | $helper->line();
43 |
44 | $helper->header('Test Ref\softrefcount');
45 | $helper->export_annotated('softrefcount($obj1)', softrefcount($obj1));
46 | $helper->export_annotated('softrefcount($obj2)', softrefcount($obj2));
47 | $helper->export_annotated('softrefcount($obj3)', softrefcount($obj3));
48 | $helper->line();
49 |
50 | $helper->header('Test Ref\softrefs');
51 |
52 | $helper->assert('Multiple soft refs reported for object with softrefs()', softrefs($obj1), [$soft_ref1a, $soft_ref1b]);
53 | $helper->dump(softrefs($obj1));
54 | $helper->line();
55 |
56 | $helper->assert('Single soft ref reported for object with softrefs()', softrefs($obj2), [$soft_ref2]);
57 | $helper->dump(softrefs($obj2));
58 | $helper->line();
59 |
60 | $helper->assert('No soft refs reported for object with softrefs()', softrefs($obj3), []);
61 | $helper->dump(softrefs($obj3));
62 | $helper->line();
63 |
64 | ?>
65 | --EXPECT--
66 | Test Ref\softrefcounted:
67 | ------------------------
68 | softrefcounted($obj1): boolean: true
69 | softrefcounted($obj2): boolean: true
70 | softrefcounted($obj3): boolean: false
71 |
72 | Test Ref\softrefcount:
73 | ----------------------
74 | softrefcount($obj1): integer: 2
75 | softrefcount($obj2): integer: 1
76 | softrefcount($obj3): integer: 0
77 |
78 | Test Ref\softrefs:
79 | ------------------
80 | Multiple soft refs reported for object with softrefs(): ok
81 | array(2) refcount(2){
82 | [0]=>
83 | object(Ref\SoftReference)#5 (2) refcount(2){
84 | ["referent":"Ref\AbstractReference":private]=>
85 | object(stdClass)#2 (0) refcount(3){
86 | }
87 | ["notifier":"Ref\AbstractReference":private]=>
88 | NULL
89 | }
90 | [1]=>
91 | object(Ref\SoftReference)#6 (2) refcount(2){
92 | ["referent":"Ref\AbstractReference":private]=>
93 | object(stdClass)#2 (0) refcount(3){
94 | }
95 | ["notifier":"Ref\AbstractReference":private]=>
96 | NULL
97 | }
98 | }
99 |
100 | Single soft ref reported for object with softrefs(): ok
101 | array(1) refcount(2){
102 | [0]=>
103 | object(Ref\SoftReference)#7 (2) refcount(2){
104 | ["referent":"Ref\AbstractReference":private]=>
105 | object(stdClass)#3 (0) refcount(2){
106 | }
107 | ["notifier":"Ref\AbstractReference":private]=>
108 | NULL
109 | }
110 | }
111 |
112 | No soft refs reported for object with softrefs(): ok
113 | array(0) refcount(2){
114 | }
115 |
--------------------------------------------------------------------------------
/scripts/replace_expect.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 |
7 | *
8 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
9 | *
10 | * For the full copyright and license information, please view the
11 | * LICENSE file that was distributed with this source or visit
12 | * http://opensource.org/licenses/MIT
13 | */
14 |
15 | $tests_dir = realpath(__DIR__ . '/../tests');
16 |
17 |
18 | $mode = 'write';
19 |
20 | $args = $argv;
21 | unset($args[0]);
22 |
23 | foreach ($argv as $i => $item) {
24 | if ($item == '--pretend') {
25 | $mode = 'pretend';
26 | unset($args[$i]);
27 | }
28 | }
29 |
30 | if (count($args) > 1) {
31 | echo 'Invalid options', PHP_EOL;
32 | exit(1);
33 | }
34 |
35 | if ($args) {
36 | $mask = str_replace(['tests/', '.phpt', '.diff'], '', array_pop($args));
37 | } else {
38 | $mask = '*';
39 | }
40 |
41 | $iterator = new GlobIterator($tests_dir . "/{$mask}.out", FilesystemIterator::KEY_AS_FILENAME);
42 |
43 | foreach ($iterator as $item) {
44 | //var_dump($item);
45 | $out_file = $iterator->key();
46 | $base_name = preg_replace('/\.out$/i', '', $iterator->key());
47 | $test_file = $base_name . '.phpt';
48 |
49 | $test_content = file_get_contents($tests_dir . '/' . $test_file);
50 |
51 | if (false !== ($pos = strpos($test_content, '--EXPECT--'))) {
52 | printf("--EXPECT-- [%s]" . PHP_EOL, $iterator->key());
53 |
54 | $test_content = substr($test_content, 0, $pos);
55 | $test_content .= '--EXPECT--' . PHP_EOL;
56 | $test_content .= file_get_contents($tests_dir . '/' . $out_file);
57 | $test_content .= PHP_EOL;
58 | file_put_contents($tests_dir . '/' . $test_file, $test_content);
59 |
60 | foreach (['.diff', '.exp', '.log', '.mem', '.out', '.php', '.sh'] as $ext) {
61 | @unlink($tests_dir . '/' . $base_name . $ext);
62 | }
63 |
64 | continue;
65 | //} elseif (0) {
66 | } elseif (false !== ($pos = strpos($test_content, '--EXPECTF--'))) {
67 |
68 | printf("--EXPECTF-- [%s]" . PHP_EOL, $iterator->key());
69 |
70 | // get replacements
71 |
72 | $tests = substr($test_content, 0, $pos);
73 | $result = file_get_contents($tests_dir . '/' . $out_file);
74 |
75 | preg_match_all('#// EXPECTF: \-\-\-(.+)#', $tests, $expectf_search);
76 | preg_match_all('#// EXPECTF: \+\+\+(.+)#', $tests, $expectf_replace);
77 |
78 | if (count($expectf_search) != count($expectf_replace)) {
79 | printf("please, edit manually [%s]: searches and replaces count doesn't match" . PHP_EOL, $iterator->key());
80 | continue;
81 | }
82 |
83 | foreach (array_combine($expectf_search[1], $expectf_replace[1]) as $search => $replace) {
84 | $replace = str_replace('\\\\n', '!!(ಠ_ಠ)!!', $replace);
85 | $replace = str_replace('\\n', "\n", $replace);
86 | $replace = str_replace('!!(ಠ_ಠ)!!', '\\\\n', $replace);
87 |
88 | $result = preg_replace($search, $replace, $result);
89 | }
90 |
91 | $test_content = $tests;
92 | $test_content .= '--EXPECTF--' . PHP_EOL;
93 | $test_content .= $result;
94 | $test_content .= PHP_EOL;
95 |
96 | if ($mode == 'pretend') {
97 | echo $result, PHP_EOL;
98 | echo PHP_EOL;
99 |
100 | } elseif ($mode = 'write') {
101 | file_put_contents($tests_dir . '/' . $test_file, $test_content);
102 |
103 | foreach (['.diff', '.exp', '.log', '.mem', '.out', '.php', '.sh'] as $ext) {
104 | @unlink($tests_dir . '/' . $base_name . $ext);
105 | }
106 | }
107 |
108 | continue;
109 | }
110 |
111 | printf("please, edit manually [%s]" . PHP_EOL, $iterator->key());
112 | }
113 |
--------------------------------------------------------------------------------
/tests/002-WeakReference-clone.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\WeakReference - clone reference
3 | --SKIPIF--
4 |
5 | --FILE--
6 | dump($ref);
21 | };
22 |
23 | $wr = new \Ref\WeakReference($obj, $notifier);
24 |
25 | $helper->export_annotated('weakrefcount($obj)', weakrefcount($obj));
26 | $helper->dump($wr);
27 | $helper->line();
28 |
29 | $wr2 = clone $wr;
30 |
31 | $helper->assert('Cloned weak reference matches original', $wr == $wr2);
32 | $helper->assert('Cloned weak reference does not match original weak reference strictly', $wr !== $wr2);
33 | $helper->line();
34 |
35 | $helper->export_annotated('weakrefcount($obj)', weakrefcount($obj));
36 | $helper->dump($wr2);
37 | $helper->line();
38 |
39 | $helper->assert('Weak references reported with cloned reference', weakrefs($obj), [$wr, $wr2]);
40 | $helper->line();
41 |
42 | $obj = null;
43 | $helper->line();
44 |
45 | $helper->assert('Cloned weak reference matches original', $wr == $wr2);
46 | $helper->assert('Cloned weak reference does not match original weak reference strictly', $wr !== $wr2);
47 | $helper->line();
48 |
49 |
50 | ?>
51 | EOF
52 | --EXPECT--
53 | weakrefcount($obj): integer: 1
54 | object(Ref\WeakReference)#4 (2) refcount(3){
55 | ["referent":"Ref\AbstractReference":private]=>
56 | object(stdClass)#2 (0) refcount(2){
57 | }
58 | ["notifier":"Ref\AbstractReference":private]=>
59 | object(Closure)#3 (2) refcount(3){
60 | ["static"]=>
61 | array(1) refcount(1){
62 | ["helper"]=>
63 | object(Testsuite)#1 (0) refcount(4){
64 | }
65 | }
66 | ["parameter"]=>
67 | array(1) refcount(1){
68 | ["$ref"]=>
69 | string(10) "" refcount(1)
70 | }
71 | }
72 | }
73 |
74 | Cloned weak reference matches original: ok
75 | Cloned weak reference does not match original weak reference strictly: ok
76 |
77 | weakrefcount($obj): integer: 2
78 | object(Ref\WeakReference)#5 (2) refcount(3){
79 | ["referent":"Ref\AbstractReference":private]=>
80 | object(stdClass)#2 (0) refcount(2){
81 | }
82 | ["notifier":"Ref\AbstractReference":private]=>
83 | object(Closure)#3 (2) refcount(4){
84 | ["static"]=>
85 | array(1) refcount(1){
86 | ["helper"]=>
87 | object(Testsuite)#1 (0) refcount(4){
88 | }
89 | }
90 | ["parameter"]=>
91 | array(1) refcount(1){
92 | ["$ref"]=>
93 | string(10) "" refcount(1)
94 | }
95 | }
96 | }
97 |
98 | Weak references reported with cloned reference: ok
99 |
100 | Notified: object(Ref\WeakReference)#5 (2) refcount(7){
101 | ["referent":"Ref\AbstractReference":private]=>
102 | NULL
103 | ["notifier":"Ref\AbstractReference":private]=>
104 | object(Closure)#3 (2) refcount(5){
105 | ["static"]=>
106 | array(1) refcount(1){
107 | ["helper"]=>
108 | object(Testsuite)#1 (0) refcount(5){
109 | }
110 | }
111 | ["parameter"]=>
112 | array(1) refcount(1){
113 | ["$ref"]=>
114 | string(10) "" refcount(1)
115 | }
116 | }
117 | }
118 | Notified: object(Ref\WeakReference)#4 (2) refcount(7){
119 | ["referent":"Ref\AbstractReference":private]=>
120 | NULL
121 | ["notifier":"Ref\AbstractReference":private]=>
122 | object(Closure)#3 (2) refcount(5){
123 | ["static"]=>
124 | array(1) refcount(1){
125 | ["helper"]=>
126 | object(Testsuite)#1 (0) refcount(5){
127 | }
128 | }
129 | ["parameter"]=>
130 | array(1) refcount(1){
131 | ["$ref"]=>
132 | string(10) "" refcount(1)
133 | }
134 | }
135 | }
136 |
137 | Cloned weak reference matches original: ok
138 | Cloned weak reference does not match original weak reference strictly: ok
139 |
140 | EOF
141 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-clone.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - clone reference
3 | --SKIPIF--
4 |
5 | --FILE--
6 | dump($ref);
21 | };
22 |
23 | $ref = new \Ref\SoftReference($obj, $notifier);
24 |
25 | $helper->export_annotated('softrefcount($obj)', softrefcount($obj));
26 | $helper->dump($ref);
27 | $helper->line();
28 |
29 | $ref2 = clone $ref;
30 |
31 | $helper->assert('Cloned soft reference matches original', $ref == $ref2);
32 | $helper->assert('Cloned soft reference does not match original soft reference strictly', $ref !== $ref2);
33 | $helper->line();
34 |
35 | $helper->export_annotated('softrefcount($obj)', softrefcount($obj));
36 | $helper->dump($ref2);
37 | $helper->line();
38 |
39 | $helper->assert('Soft references reported with cloned reference', softrefs($obj), [$ref, $ref2]);
40 | $helper->line();
41 |
42 | $obj = null;
43 | $helper->line();
44 |
45 | $helper->assert('Cloned soft reference matches original', $ref == $ref2);
46 | $helper->assert('Cloned soft reference does not match original soft reference strictly', $ref !== $ref2);
47 | $helper->line();
48 |
49 |
50 | ?>
51 | EOF
52 | --EXPECT--
53 | softrefcount($obj): integer: 1
54 | object(Ref\SoftReference)#4 (2) refcount(3){
55 | ["referent":"Ref\AbstractReference":private]=>
56 | object(stdClass)#2 (0) refcount(2){
57 | }
58 | ["notifier":"Ref\AbstractReference":private]=>
59 | object(Closure)#3 (2) refcount(3){
60 | ["static"]=>
61 | array(1) refcount(1){
62 | ["helper"]=>
63 | object(Testsuite)#1 (0) refcount(4){
64 | }
65 | }
66 | ["parameter"]=>
67 | array(1) refcount(1){
68 | ["$ref"]=>
69 | string(10) "" refcount(1)
70 | }
71 | }
72 | }
73 |
74 | Cloned soft reference matches original: ok
75 | Cloned soft reference does not match original soft reference strictly: ok
76 |
77 | softrefcount($obj): integer: 2
78 | object(Ref\SoftReference)#5 (2) refcount(3){
79 | ["referent":"Ref\AbstractReference":private]=>
80 | object(stdClass)#2 (0) refcount(2){
81 | }
82 | ["notifier":"Ref\AbstractReference":private]=>
83 | object(Closure)#3 (2) refcount(4){
84 | ["static"]=>
85 | array(1) refcount(1){
86 | ["helper"]=>
87 | object(Testsuite)#1 (0) refcount(4){
88 | }
89 | }
90 | ["parameter"]=>
91 | array(1) refcount(1){
92 | ["$ref"]=>
93 | string(10) "" refcount(1)
94 | }
95 | }
96 | }
97 |
98 | Soft references reported with cloned reference: ok
99 |
100 | Notified: object(Ref\SoftReference)#5 (2) refcount(7){
101 | ["referent":"Ref\AbstractReference":private]=>
102 | object(stdClass)#2 (0) refcount(2){
103 | }
104 | ["notifier":"Ref\AbstractReference":private]=>
105 | object(Closure)#3 (2) refcount(5){
106 | ["static"]=>
107 | array(1) refcount(1){
108 | ["helper"]=>
109 | object(Testsuite)#1 (0) refcount(5){
110 | }
111 | }
112 | ["parameter"]=>
113 | array(1) refcount(1){
114 | ["$ref"]=>
115 | string(10) "" refcount(1)
116 | }
117 | }
118 | }
119 | Notified: object(Ref\SoftReference)#4 (2) refcount(7){
120 | ["referent":"Ref\AbstractReference":private]=>
121 | object(stdClass)#2 (0) refcount(2){
122 | }
123 | ["notifier":"Ref\AbstractReference":private]=>
124 | object(Closure)#3 (2) refcount(5){
125 | ["static"]=>
126 | array(1) refcount(1){
127 | ["helper"]=>
128 | object(Testsuite)#1 (0) refcount(5){
129 | }
130 | }
131 | ["parameter"]=>
132 | array(1) refcount(1){
133 | ["$ref"]=>
134 | string(10) "" refcount(1)
135 | }
136 | }
137 | }
138 |
139 | Cloned soft reference matches original: ok
140 | Cloned soft reference does not match original soft reference strictly: ok
141 |
142 | EOF
143 |
--------------------------------------------------------------------------------
/php_ref_notifier_exception.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the pinepain/php-ref PHP extension.
3 | *
4 | * Copyright (c) 2016-2018 Bogdan Padalko
5 | *
6 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
7 | *
8 | * For the full copyright and license information, please view the
9 | * LICENSE file that was distributed with this source or visit
10 | * http://opensource.org/licenses/MIT
11 | */
12 |
13 | #include "php_ref_notifier_exception.h"
14 | #include "php_ref.h"
15 | #include "zend_exceptions.h"
16 |
17 |
18 | zend_class_entry *php_ref_notifier_exception_class_entry;
19 | #define this_ce php_ref_notifier_exception_class_entry
20 |
21 |
22 | static zend_object *php_ref_notifier_exception_ctor(zend_class_entry *ce)
23 | {
24 | zval obj, thrown;
25 | zend_object *object;
26 |
27 | Z_OBJ(obj) = object = ce->parent->create_object(ce);
28 |
29 | array_init_size(&thrown, 0);
30 | zend_update_property(php_ref_notifier_exception_class_entry, &obj, ZEND_STRL("exceptions"), &thrown);
31 |
32 | return object;
33 | }
34 |
35 |
36 | void php_ref_create_notifier_exception(zval *exception, const char *message, zval *thrown)
37 | {
38 | object_init_ex(exception, this_ce);
39 | zend_update_property_string(zend_ce_exception, exception, ZEND_STRL("message"), message);
40 | zend_update_property(php_ref_notifier_exception_class_entry, exception, ZEND_STRL("exceptions"), thrown);
41 | }
42 |
43 | static PHP_METHOD(NotifierException, __construct)
44 | {
45 | zend_string *message = NULL;
46 | zend_long code = 0;
47 |
48 | zval tmp;
49 | zval *exceptions = NULL;
50 | zval *previous = NULL;
51 |
52 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SalO!", &message, &exceptions, &code, &previous, zend_ce_throwable) == FAILURE) {
53 | return;
54 | }
55 |
56 | if (message) {
57 | zend_update_property_str(zend_ce_exception, getThis(), ZEND_STRL("message"), message);
58 | }
59 |
60 | if (exceptions) {
61 | zend_update_property(this_ce, getThis(), ZEND_STRL("exceptions"), exceptions);
62 | } else {
63 | array_init_size(&tmp, 0);
64 | zend_update_property(this_ce, getThis(), ZEND_STRL("exceptions"), &tmp);
65 | zval_dtor(&tmp);
66 | }
67 |
68 | if (code) {
69 | zend_update_property_long(zend_ce_exception, getThis(), ZEND_STRL("code"), code);
70 | }
71 |
72 | if (previous) {
73 | zend_update_property(zend_ce_exception, getThis(), ZEND_STRL("previous"), previous);
74 | }
75 | }
76 |
77 | static PHP_METHOD(NotifierException, getExceptions)
78 | {
79 | zval rv;
80 |
81 | if (zend_parse_parameters_none() == FAILURE) {
82 | return;
83 | }
84 |
85 | RETVAL_ZVAL(zend_read_property(php_ref_notifier_exception_class_entry, getThis(), ZEND_STRL("exceptions"), 0, &rv), 1, 0);
86 | }
87 |
88 |
89 | ZEND_BEGIN_ARG_INFO_EX(arginfo_notifier_exception___construct, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0)
90 | ZEND_ARG_INFO(0, message)
91 | ZEND_ARG_INFO(0, exceptions)
92 | ZEND_ARG_INFO(0, code)
93 | ZEND_ARG_INFO(0, previous)
94 | ZEND_END_ARG_INFO()
95 |
96 | ZEND_BEGIN_ARG_INFO_EX(arginfo_notifier_exception_getExceptions, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0)
97 | ZEND_END_ARG_INFO()
98 |
99 |
100 | static const zend_function_entry php_ref_notifier_exception_methods[] = {
101 | PHP_ME(NotifierException, __construct, arginfo_notifier_exception___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
102 | PHP_ME(NotifierException, getExceptions, arginfo_notifier_exception_getExceptions, ZEND_ACC_PUBLIC)
103 |
104 | PHP_FE_END
105 | };
106 |
107 |
108 | PHP_MINIT_FUNCTION (php_ref_notifier_exception)
109 | {
110 | zend_class_entry ce;
111 |
112 | INIT_NS_CLASS_ENTRY(ce, PHP_REF_NS, "NotifierException", php_ref_notifier_exception_methods);
113 | this_ce = zend_register_internal_class_ex(&ce, zend_ce_exception);
114 | /*this_ce->create_object = php_ref_notifier_exception_ctor;*/
115 |
116 | zend_declare_property_null(this_ce, ZEND_STRL("exceptions"), ZEND_ACC_PRIVATE);
117 |
118 |
119 | return SUCCESS;
120 | }
121 |
--------------------------------------------------------------------------------
/tests/004-SoftReference-notified_prevent_destoying.phpt:
--------------------------------------------------------------------------------
1 | --TEST--
2 | Ref\SoftReference - prevent original object from being destroyed
3 | --SKIPIF--
4 |
5 | --FILE--
6 | assert('Notifier called', true);
23 | $helper->assert('Notifier get 1 argument', sizeof(func_get_args()) === 1);
24 | $helper->assert('Notifier get soft reference as it argument', $reference instanceof Ref\SoftReference);
25 | $helper->assert('Original object is null', null === $obj);
26 | $helper->assert('Soft reference in notifier is not null', null !== $reference->get());
27 | $helper->assert('Soft reference in notifier points to original object', $reference->get() instanceof \WeakTests\TrackingDtor);
28 | $helper->space();
29 |
30 | $obj_copy = $reference->get();
31 | });
32 |
33 | $helper->header('When referent object alive');
34 | $helper->assert('Referent object alive', $sr->get() === $obj);
35 |
36 | $helper->line();
37 | $helper->dump($sr);
38 | $helper->space();
39 |
40 | $obj = null;
41 |
42 | $helper->header('When referent object was nullified but reference to it stored from notifier');
43 | $helper->assert('Original variable holds null', null === $obj);
44 | $helper->assert('Object copy is not null', null !== $obj_copy);
45 | $helper->assert('Object copy dtor was not called', false === is_obj_destructor_called($obj_copy));
46 | $helper->assert('Referent object alive', $sr->get() === $obj_copy);
47 |
48 | $helper->line();
49 | $helper->dump($sr);
50 | $helper->line();
51 |
52 | $sr = null;
53 | $obj_copy = null;
54 |
55 | ?>
56 | EOF
57 | --EXPECT--
58 | When referent object alive:
59 | ---------------------------
60 | Referent object alive: ok
61 |
62 | object(Ref\SoftReference)#3 (2) refcount(3){
63 | ["referent":"Ref\AbstractReference":private]=>
64 | object(WeakTests\TrackingDtor)#2 (0) refcount(2){
65 | }
66 | ["notifier":"Ref\AbstractReference":private]=>
67 | object(Closure)#4 (2) refcount(2){
68 | ["static"]=>
69 | array(3) refcount(1){
70 | ["obj"]=>
71 | &object(WeakTests\TrackingDtor)#2 (0) refcount(2){
72 | }
73 | ["obj_copy"]=>
74 | &NULL
75 | ["helper"]=>
76 | &object(Testsuite)#1 (0) refcount(2){
77 | }
78 | }
79 | ["parameter"]=>
80 | array(1) refcount(1){
81 | ["$reference"]=>
82 | string(10) "" refcount(1)
83 | }
84 | }
85 | }
86 |
87 |
88 | Notifier called: ok
89 | Notifier get 1 argument: ok
90 | Notifier get soft reference as it argument: ok
91 | Original object is null: ok
92 | Soft reference in notifier is not null: ok
93 | Soft reference in notifier points to original object: ok
94 |
95 |
96 | When referent object was nullified but reference to it stored from notifier:
97 | ----------------------------------------------------------------------------
98 | Original variable holds null: ok
99 | Object copy is not null: ok
100 | Object copy dtor was not called: ok
101 | Referent object alive: ok
102 |
103 | object(Ref\SoftReference)#3 (2) refcount(3){
104 | ["referent":"Ref\AbstractReference":private]=>
105 | object(WeakTests\TrackingDtor)#2 (0) refcount(2){
106 | }
107 | ["notifier":"Ref\AbstractReference":private]=>
108 | object(Closure)#4 (2) refcount(2){
109 | ["static"]=>
110 | array(3) refcount(1){
111 | ["obj"]=>
112 | &NULL
113 | ["obj_copy"]=>
114 | &object(WeakTests\TrackingDtor)#2 (0) refcount(2){
115 | }
116 | ["helper"]=>
117 | &object(Testsuite)#1 (0) refcount(2){
118 | }
119 | }
120 | ["parameter"]=>
121 | array(1) refcount(1){
122 | ["$reference"]=>
123 | string(10) "" refcount(1)
124 | }
125 | }
126 | }
127 |
128 | WeakTests\TrackingDtor's destructor called
129 | EOF
130 |
--------------------------------------------------------------------------------
/scripts/refresh-package-xml.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 |
8 | *
9 | * Licensed under the MIT license: http://opensource.org/licenses/MIT
10 | *
11 | * For the full copyright and license information, please view the
12 | * LICENSE file that was distributed with this source or visit
13 | * http://opensource.org/licenses/MIT
14 | */
15 |
16 |
17 | chdir(__DIR__ . DIRECTORY_SEPARATOR . '..');
18 |
19 | $contents = [
20 | 'stubs' => 'doc',
21 | 'tests' => 'test',
22 | 'config.m4' => 'src',
23 | 'config.w32' => 'src',
24 | 'LICENSE' => 'doc',
25 | 'php_ref.h' => 'src',
26 | 'php_ref_functions.c' => 'src',
27 | 'php_ref_functions.h' => 'src',
28 | 'php_ref_notifier_exception.c' => 'src',
29 | 'php_ref_notifier_exception.h' => 'src',
30 | 'php_ref_reference.c' => 'src',
31 | 'php_ref_reference.h' => 'src',
32 | 'README.md' => 'doc',
33 | 'ref.c' => 'src',
34 | ];
35 |
36 | $rules = [
37 | 'test' => [
38 | '/\.phpt$/',
39 | '/^\..+\.php$/',
40 | ],
41 | ];
42 |
43 |
44 | $files = [];
45 |
46 | $files[] = '';
47 |
48 | foreach ($contents as $location => $role) {
49 | if (is_dir($location)) {
50 |
51 | $dir_files = [];
52 | /** @var SplFileInfo $filename */
53 | foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($location)) as $filename) {
54 | if ($filename->isDir()) {
55 | continue;
56 | }
57 |
58 | $location = $filename->getPathname();
59 |
60 | if (!is_file($location)) {
61 | throw new Exception("'{$location}' is not a file");
62 | }
63 |
64 |
65 | if (isset($rules[$role])) {
66 | $matches = false;
67 | foreach ($rules[$role] as $rule) {
68 | if ($matches = preg_match($rule, $filename->getFilename())) {
69 | break;
70 | }
71 | }
72 |
73 | if (!$matches) {
74 | continue;
75 | }
76 | }
77 |
78 | $dir_files[] = " ";
79 | }
80 |
81 | sort($dir_files);
82 |
83 | $files = array_merge($files, $dir_files);
84 |
85 | continue;
86 | }
87 |
88 | if (!is_file($location)) {
89 | throw new Exception("'{$location}' is not a file");
90 | }
91 |
92 | $files[] = " ";
93 | }
94 |
95 | $files[] = ' ';
96 |
97 | $package = file_get_contents('package.xml');
98 |
99 | $start = preg_quote('');
100 | $end = preg_quote('');
101 |
102 | $package = preg_replace("/{$start}.+{$end}/s", implode("\n", $files), $package);
103 |
104 | $datetime = new DateTime();
105 | $package = preg_replace("/\.+\<\/date\>/", '' . $datetime->format('Y-m-d') . '', $package);
106 | $package = preg_replace("/\