colder / php-weakref Goto Github PK
View Code? Open in Web Editor NEWPECL extension that implements weak references and weak maps in PHP
Home Page: http://pecl.php.net/weakref
License: Other
PECL extension that implements weak references and weak maps in PHP
Home Page: http://pecl.php.net/weakref
License: Other
So I was excited to see that WeakRef is now available to install for php 7, but it's been so long since I actually installed WeakRef I'm not sure if I'm missing a step.
I installed WeakRef via pecl
as it seemed the easiest way, and added extension=weakref.so
in a file under /etc/php/7.0/fpm/conf.d
, which seemed the neatest place to put it.
When I look in phpinfo()
I can verify that Weakref is loaded, but the class is not available for use. Are there any additional requirements that I may be missing?
I have an approach based on replacing the handlers
instead of just the destructor handler working at weakreference_bc
for https://github.com/TysonAndre/pecl-weakreference_bc/ targeting 7.0-7.4 - it'll work as long as it isn't used with other extensions doing the same thing to an object.
The actual impact of changing spl_object_hash may be limited
With this repo being abandoned, and https://wiki.php.net/rfc/deprecate_dynamic_properties recently passing, some libraries/applications may need an approach to replace former uses of dynamic properties - having a WeakMap polyfill would help let them continue to support PHP <= 7.4 and allow those users to use newer application/library releases in older php versions before upgrading.
Related to #31
For #28 , this did not crash in php's development server in php 7.2
<?php
$obj = (object) [
"someProperty" => "someValue"
];
$ref = WeakReference::create($obj);
echo $ref->get()->someProperty;
From PHP License:
Fedora Packaging Guidelines requires (to respect the License term) that each RPM includes the LICENSE file, when provided by upstream, and to request for it when missing.
So I do.
http://fedoraproject.org/wiki/Packaging/LicensingGuidelines#License_Text
Great, let me know if I can be of assistance.
Dear Christian,
Thanks for this report, people with github accounts usually report
them as issues on the github project page.
From the error it seems like it is an mistake on my side, I probably
did not check that it still worked on 5.3 when releasing 0.2.1. PHP
defines various macros that are not always available in every
versions.
I will fix it as soon as I can, which will probably coincide with when
I return from holidays :)
Best,
On Tue, Jul 24, 2012 at 12:21 AM, Christian Csar
<> wrote:
Etienne,
I'm using your WeakRef extension for a library I'm working on as
weak references are the correct solution, and I'm running into the
below error which looks to be a linking error vs an error in the php
code. If there's a more appropriate support path, please let me know,
or CC it as appropriate (i.e. filing the first bug in the bugtracker
or the PECL dev list). Weakref lists itself compatible with PHP 5.3 -
5.5 and is giving an error on 5.3.3 debian squeeze but not 5.4.4
fedora 17. Any guidance you can provide would be appreciated. I am
happy to provide additional information as needed. Strace suggests
that weakref.so is successfully being opened (and I believe such
errors would result in a different message).Given the file weakRefTest.php
acquire(); ?>"php weakRefTest.php" gives
"php: symbol lookup error: /usr/lib/php5/20090626/weakref.so:
undefined symbol: ZVAL_COPY_VALUE"on our Debian dev server using the following:
$pecl info WeakRefABOUT PECL.PHP.NET/WEAKREF-0.2.1
Release Type PECL-style PHP extension (source code)
Name Weakref
Channel pecl.php.net
Summary Implementation of weak references
Description A weak reference provides a gateway to an object
without preventing that object from being
collected by the garbage collector (GC).
Maintainers Etienne Kneuss [email protected] (lead)
Release Date 2012-06-19 15:09:07
Release Version 0.2.1 (beta)
API Version 0.2.1 (beta)
License PHP (http://www.php.net/license)
Release Notes - Fixes crashes and bugs caused by zval
splitting.
Required Dependencies PHP version 5.3.0-5.5.0
PEAR installer version 1.4.0b1 or newer
Not Compatible with PHP versions
6.0.0
package.xml version 2.0
Last Modified 2012-07-20 21:13
Previous Installed - None -
Version$pear version
PEAR Version: 1.9.4
PHP Version: 5.3.3-7+squeeze13
Zend Engine Version: 2.3.0
Running on: Linux www01 2.6.32-5-amd64 #1 SMP Sun May 6 04:00:17 UTC 2012 x86_64On my Fedora 17 dev machine with PHP and php-pear from the fedora
repositories, and weakref from PECL, the code appears to work fine
with no error being given.$pear version
PEAR Version: 1.9.4
PHP Version: 5.4.4
Zend Engine Version: 2.4.0
Running on: Linux laurence 3.4.4-5.fc17.x86_64 #1 SMP Thu Jul 5
20:20:59 UTC 2012 x86_64
$pecl info WeakRefABOUT PECL.PHP.NET/WEAKREF-0.2.1
Release Type PECL-style PHP extension (source code)
Name Weakref
Channel pecl.php.net
Summary Implementation of weak references
Description A weak reference provides a gateway to an object
without preventing that object from being
collected by the garbage collector (GC).
Maintainers Etienne Kneuss [email protected] (lead)
Release Date 2012-06-19 15:09:07
Release Version 0.2.1 (beta)
API Version 0.2.1 (beta)
License PHP (http://www.php.net/license)
Release Notes - Fixes crashes and bugs caused by zval
splitting.
Required Dependencies PHP version 5.3.0-5.5.0
PEAR installer version 1.4.0b1 or newer
Not Compatible with PHP versions
6.0.0
package.xml version 2.0
Last Modified 2012-07-23 22:07
Previous Installed - None -
From wr_store.c:L91:
((zend_object_handlers *)ref_obj->handlers)->dtor_obj = wr_store_tracked_object_dtor;
but handlers specified as const zend_object_handlers *handlers
and modifying pointer to const value is something that specified as an undefined behavior.
Can you pleas clarify what is the reason do cast away constness apart of having handlers pointer value the same so spl_object_hash()
will also be the same?
$ grep VERSION Weakref-0.2.3/php_weakref.h
#define PHP_WEAKREF_VERSION "0.0.1-alpha"
Currently the PECL installer only allows up to and including PHP 5.5.0
The extension still appears to be compatible with the 5.5.x branch
The page will be processed right, and the request will be fulfilled, but the server will exit with exit code 9 after the same page is requested again. Weakref works fine before that. I have set up a small test to confirm that it is the extension:
<?php
$obj = (object) [
"someProperty" => "someValue"
];
$ref = new Weakref($obj);
// The following is not required for the exit to occur, but confirms that the extension works.
echo $ref->get()->someProperty;
After processing this page, the server will exit. Requesting the page again will crash the server. No error whatsoever is thrown at any point, except for the exit code. I have no idea how I would go around to get a log of an error like this.
Software:
Windows 10
PHP 7.0.11 x64 VC14 thread-safe
Weakref 0.3.2 (for PHP 7.0 TS x64)
Under PHP 5.4.4-14+deb7u14 with Weakref-0.2.4, the following segfaults:
<?php
class RefHolder {
function __construct($o) { $this->o = new WeakRef($o); }
}
$o = new Stdclass();
$map = new WeakMap();
$map[$o] = [];
//unset($map[$o]);
$map[$o] = new RefHolder($o);
$o = new Stdclass(); // segfault
No extensions outside of weakref loaded. That is, ran as php -n -d extension=weakref.so segfault.php
.
Uncommenting the unset() seems to work around the problem.
Hello!
I saw that you have a milestone for 0.3 - php7.
Right now I'm trying to move to PHP7 and I would like some information about this extension being upgraded (and when it's happening!).
Thank you for developing this extension!
PHP5.3.2 and Weakref 0.1.0 (beta)
Allow traversing weakmaps using
foreach ($wm as $obj => $data) {
...
}
I've been finding segfaults in production.
I'm not using weakref directly but it is part of the dependencies for a library that I'm using (https://github.com/OggettoWeb/messenger/wiki/Installation-&-Setup#weakref), so I haven't got steps to reproduce.
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/sbin/php-fpm7.0...Reading symbols from /usr/lib/debug/.build-id/c7/7525c868f3a9e62665b89857f9bac4b640f132.debug...done.
done.
[New LWP 29729]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `php-fpm: pool www '.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x00007f9aa244e1c6 in wr_store_tracked_object_dtor (ref_obj=0x7f9aae09a3c0) at /tmp/pear/temp/Weakref/wr_store.c:63
#2 0x00007f9ab0b6b72b in zend_objects_store_del (object=0x7f9aae09a3c0) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_objects_API.c:160
#3 0x00007f9ab0b31486 in _zval_dtor_func_for_ptr (p=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_variables.c:109
#4 0x00007f9ab0bb732a in i_free_compiled_variables (execute_data=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_execute.c:2061
#5 zend_leave_helper_SPEC () at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:531
#6 0x00007f9ab0b6f44b in execute_ex (ex=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:414
#7 0x00007f9ab0b239f9 in dtrace_execute_ex (execute_data=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_dtrace.c:83
#8 0x00007f9aa1775c62 in nr_php_execute_enabled () from /usr/lib/php/20151012/newrelic.so
#9 0x00007f9aa17763b2 in nr_php_execute () from /usr/lib/php/20151012/newrelic.so
#10 0x00007f9ab0bacc30 in ZEND_DO_FCALL_SPEC_HANDLER () at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:800
#11 0x00007f9ab0b6f44b in execute_ex (ex=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:414
#12 0x00007f9ab0b239f9 in dtrace_execute_ex (execute_data=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_dtrace.c:83
#13 0x00007f9aa1775c62 in nr_php_execute_enabled () from /usr/lib/php/20151012/newrelic.so
#14 0x00007f9aa17763b2 in nr_php_execute () from /usr/lib/php/20151012/newrelic.so
#15 0x00007f9ab0bacc30 in ZEND_DO_FCALL_SPEC_HANDLER () at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:800
#16 0x00007f9ab0b6f44b in execute_ex (ex=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:414
#17 0x00007f9ab0b239f9 in dtrace_execute_ex (execute_data=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_dtrace.c:83
#18 0x00007f9aa1775c62 in nr_php_execute_enabled () from /usr/lib/php/20151012/newrelic.so
#19 0x00007f9aa17763b2 in nr_php_execute () from /usr/lib/php/20151012/newrelic.so
#20 0x00007f9ab0bacc30 in ZEND_DO_FCALL_SPEC_HANDLER () at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:800
#21 0x00007f9ab0b6f44b in execute_ex (ex=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:414
#22 0x00007f9ab0b239f9 in dtrace_execute_ex (execute_data=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_dtrace.c:83
#23 0x00007f9aa1775c62 in nr_php_execute_enabled () from /usr/lib/php/20151012/newrelic.so
#24 0x00007f9aa17763b2 in nr_php_execute () from /usr/lib/php/20151012/newrelic.so
#25 0x00007f9ab0bacc30 in ZEND_DO_FCALL_SPEC_HANDLER () at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:800
#26 0x00007f9ab0b6f44b in execute_ex (ex=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:414
#27 0x00007f9ab0b239f9 in dtrace_execute_ex (execute_data=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_dtrace.c:83
#28 0x00007f9aa1775e46 in nr_php_execute_enabled () from /usr/lib/php/20151012/newrelic.so
#29 0x00007f9aa17763b2 in nr_php_execute () from /usr/lib/php/20151012/newrelic.so
#30 0x00007f9ab0bb866f in zend_execute (op_array=op_array@entry=0x7f9aae07f000, return_value=return_value@entry=0x0)
at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend_vm_execute.h:458
#31 0x00007f9ab0b33034 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=3) at /build/php7.0-RID4hL/php7.0-7.0.6/Zend/zend.c:1427
#32 0x00007f9ab0ad6d28 in php_execute_script (primary_file=0x7fff939f3420) at /build/php7.0-RID4hL/php7.0-7.0.6/main/main.c:2494
#33 0x00007f9ab09c7d7c in main (argc=<optimized out>, argv=<optimized out>) at /build/php7.0-RID4hL/php7.0-7.0.6/sapi/fpm/fpm/fpm_main.c:1968
(gdb) frame 1
#1 0x00007f9aa244e1c6 in wr_store_tracked_object_dtor (ref_obj=0x7f9aae09a3c0) at /tmp/pear/temp/Weakref/wr_store.c:63
63 /tmp/pear/temp/Weakref/wr_store.c: No such file or directory.
Also don't have any experience with C or dumps. If I send the dump file, can it be looked into?
The libraries can still work without weakref, so I've just disabled weakref for now.
Hi again, Ive done some more tests and thought a little more about it.
Calling an undefined method -> SegFault instead of Fatal Error
Found a new strange problem :
<?
$obj = new StdClass() ;
$ref = new WeakRef ($obj) ;
$obj = $ref -> get() ; //Seems to be the cause, some kind of "cyclic reference"?
//unset ($obj) ; //Avoids SegFault
unset ($ref) ; // Throws SegFault
?>
As a suggestion, to avoid dependence on an unstable extension, I thought on an alternative that just tracks "refcounts". The method get increments an internal count attribute, and its counterpart method free decreases it. If it is possible to extend WeakRef and just add an empty method free, the switch would be easy and the performance penalty often negligible. Instead of calling the free method, one could call a function free_WeakRef ($ref) ;
and there, call the method, so this function could be silenced when working with real WeakRefs, but...
I attach the example code :
<?
function linha ($cadea) {
echo $cadea."<br/>\n" ;
@ob_end_flush() ;
flush() ;
}
if (! class_exists ('WeakRef')) {
class WeakRef {
private $obj ;
public static $fake = 1 ;
public function __construct ($obj) {
$this -> acq = 0 ;
if (($type = gettype ($obj)) != 'object') {
trigger_error (__CLASS__.'::__construct() expects parameter 1 to be object, '.$type.' given', E_USER_WARNING) ;
$this -> obj = null ;
$this -> refs = 0 ;
}
$this -> obj = $obj ;
$this -> refs = 1 ;
}
public function acquire() {
if (! $this -> refs || $this -> acq)
return false ;
$this -> acq = 1 ;
return true ;
}
public function release() {
if (! $this -> acq)
return false ;
if (! $this -> refs)
$this -> obj = null ;
$this -> acq = 0 ;
return true ;
}
public function free() {
if (! $this -> refs)
return false ;
$this -> refs -- ;
if (! $this -> refs && ! $this -> acq)
$this -> obj = null ;
return true ;
}
public function valid() {
if (! $this -> refs && ! $this -> acq)
return false ;
return true ;
}
public function get() {
if ($this -> refs || $this -> acq)
$this -> refs ++ ;
return $this -> obj ;
}
public function __destruct() {
linha ('DESTR_weak') ;
}
}
function free_WeakRef ($obj) {
$obj -> free() ;
}
} else {
function free_WeakRef ($obj) {}
}
class class1 {
private static $insts = array() ;
public function __construct ($context) {
$this -> context = $context ;
}
public static function inst ($context) {
if (! isset (self::$insts [$context])/* || ! self::$insts [$this -> context] -> valid()*/)
self::$insts [$context] = new WeakRef ($inst = new self ($context)) ;
else
$inst = self::$insts [$context] -> get() ;
return $inst ;
}
public function __destruct() {
unset (self::$insts [$this -> context]) ;
linha ('DESTR_obj') ;
}
public function free() {
//if (isset (WeakRef::fake)) { // Agnostic to implementation
free_WeakRef (self::$insts [$this -> context]) ;
/*
//Implemented throw free_WeakRef and __destruct, old way :
if (! isset (self::$insts [$this -> context]) || ! self::$insts [$this -> context] -> valid())
return false ;
self::$insts [$this -> context] -> free() ;
if (! self::$insts [$this -> context] -> valid())
unset (self::$insts [$this -> context]) ;
*/
}
}
$obj1 = class1::inst ('context1') ;
$obj1 -> free() ;
unset ($obj1) ; // ->> Object is freed
linha ('FIN') ;
?>
Another interesting case for allowing extensions, a WeakRef wrapper specific for a class class1 : WR_class1
<?
$wr_obj1 = new WR_class1 ($id) ;
$aux = $wr_obj1 -> get() ;
?>
The wrapper class could store the id and guarantee that the get will always return a valid object, storing the $id and reinstantiating when the object gets lost.
Further with this idea, delegate what to do when a ref becomes invalid, the wrapper could hide completely this extra step throw overloading methods, so $wrapper -> get() -> method()
could become $wrapper -> method()
.
Another reason for not being a final class, after session serialization the WeakRef becomes always invalid, even when the object gets also independently serialized. In the same case, strong references are kept after this process. Just by extending WeakReaf, this could be avoided with custom magic sleep/wakeup methods. But could be also be considered a bug, or a desired behavior.
I dont know a lot about extensions, and nothing when OOP comes into play, but I think that making this function extendable could be a plus and just a last thought, exposing an update method, maybe protected to recover a weakly referenced object when lost, would be needed.
imagine the following:
$x = new WeakRef($obj);
$x->onLoss(function() use($map){
echo "the object was garbage collected";
$map->remove($weakref);
});
// or even...
$x->onBeforeLoss(function($object){
echo "the object is about to be garbage collected";
$map->save($object->serialize());
// $weakref->acquire(); -> triggers "you aren't allowed to acquire a strong reference here"
});
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.