GithubHelp home page GithubHelp logo

colder / php-weakref Goto Github PK

View Code? Open in Web Editor NEW
36.0 36.0 13.0 78 KB

PECL extension that implements weak references and weak maps in PHP

Home Page: http://pecl.php.net/weakref

License: Other

C 62.58% PHP 12.00% GDB 24.56% M4 0.49% JavaScript 0.37%

php-weakref's People

Contributors

colder avatar jille avatar marc-mabe avatar pierrejoye avatar remicollet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

php-weakref's Issues

Possible PHP 5.3 Compat issue

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 WeakRef

ABOUT 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_64

On 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 WeakRef

ABOUT 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 -

Observe gc events for the weakref? Would it work?

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"
});

Objections to publishing a polyfill for PHP's WeakMap/WeakReference based on this repo?

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.

  • EDIT: I now realize this has the drawback mentioned in #21 (comment) (spl_object_hash replaced the last 16 digits with 0 in php 8.0 (which I see you saw), but this extension doesn't target php 8.0) (not an issue since 7.0.3)

The actual impact of changing spl_object_hash may be limited

  • spl_object_id is used in many applications now, instead, and symfony/polyfill-php72 will properly extract the id from the first 16 characters of the hash by xoring with a known hash for an object id
  • SplObjectStorage base class only uses the object id for a key internally

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.

  1. Are there objections to creating a new repo based on this, following the PHP API instead of this for WeakMap
  2. Are there any less obvious roadblocks other than replacing the destructor(dtor) this project faced (e.g. incompatibilities with common extensions)?

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;

php7-fpm segfault

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.

Installation Requirements?

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?

Use of Weakref makes PHP development server exit on next request

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)

Strange SegFault and some more thoughts

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.

WeakMap + WeakRef Segfault

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.

Traverse WeakMap

Allow traversing weakmaps using

foreach ($wm as $obj => $data) {
  ...
}

PHP7 support

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!

__destruct

PHP5.3.2 and Weakref 0.1.0 (beta)

  1. Not documented as a final class.
  2. Trying to free (unset) the Weakref object inside the __destructor of the main object (the weakly referenced one)... causes SegFault.

Modifying const data

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.