unset a reference of property object

php.internals

Glash Gnome

4 years ago
Hello, I am developing a PHP extension. I can't reproduce the behavior of references of Zend/PHP. Here is some Code illustrating Zend's behavior: <?php class Foo { public $baz = array(1);} $foo = new Foo(); $ref = &$foo->baz; $foo->baz = [123];//set array has reference var_dump($foo); Output ------------------------ object(Foo)#1 (1) { ["baz"]=> &array(1) { [0]=> int(123) } } -------------------------------- Note the symbol ( &) output from the var_dump(); Now I add unset($ref) in my code <?php class Foo { public $baz = array(1);} $foo = new Foo(); $ref = &$foo->baz; //unset($ref);// kill reference $foo->baz = [123];// set array has reference unset($ref) ;// kill reference var_dump($foo); ------------------------ object(Foo)#1 (1) { ["baz"]=> array(1) { [0]=> int(123) } } -------------------------------- Note that the symbol (&) has disappeared from the output of var_dump(); I would like to reproduce this behavior but I don't know which method of zend_object_handlers allows to remove( Z_UNREF) the reference. Thank you for your help

Glash Gnome

4 years ago
Out of politeness I answer myself, PHP_FUNCTION(var_dump) -> php_var_dump() -> zend_std_get_properties_for() // Zend object handler get_properties_for -> obj->handlers->get_debug_info(obj, &is_temp); // Zend object handler get_debug_info -> zend_std_get_properties();// Zend object handler get_properties -> rebuild_object_properties() -> _zend_hash_append_ind() => ZVAL_INDIRECT(&p->val, ptr); // do the trick( Z_TYPE change) TODO: Find out how to manage the IS_INDIRECT So to reproduce the default php behavior I can implement the get_debug_info handler. I'm still trying to figure out how to modify this line : void my_get_debug_info() { // ... // Z_REFCOUNT(intern->data)==1 // Z_TYPE(intern->data)==IS_REFERENCE // Z_TYPE(Z_REF(intern->data)->val)==IS_ARRAY zval zdata; ZVAL_COPY(&zdata, &intern->data);// Why do I have to hide that it's a reference ? zend_hash_str_update(debug_info, "data", sizeof("data")-1, &zdata); // ... return debug_info; } my_handlers.get_debug_info = my_get_debug_info; struct _my {// intern structure zval data;// array of unsigned int zend_object std; }; Le sam. 9 avr. 2022 à 15:42, Glash Gnome <glash.gnome@gmail.com> a écrit :

Glash Gnome

4 years ago
Q1: "how to modify this line to reproduce the behavior of PHP" A1: /* {{{ vendor_my_get_debug_info */ static HashTable* vendor_my_get_debug_info(zend_object *object, int *is_temp) { vendor_my *intern = ZOBJ_TO_VENDOR_MY(object); HashTable *debug_info=NULL, *std_props=NULL; *is_temp = 1; std_props = zend_std_get_properties(object); debug_info = zend_array_dup(std_props); zval zdata; if (Z_ISREF(intern->data) && Z_REFCOUNT(intern->data)<2) {// If the reference is no longer used by the PHP-user ZVAL_COPY(&zdata, &Z_REF(intern->data)->val);// hide reference (for compatibility) } else { ZVAL_COPY(&zdata, &intern->data);// show reference (for debugging ???) } zend_hash_str_update(debug_info, "data", sizeof("data")-1, &zdata); return debug_info; } /* }}} */ Q2: "Why do I have to hide that it's a reference ?" A2: For historical( debugging) raison, see : https://github.com/php/php-src/blob/master/ext/standard/var.c#L202 I think it's a bad idea to show & but it doesn't really matter. In my case I think it's best never to show the reference : zval zdata; ZVAL_COPY(&zdata, Z_ISREF(intern->data) ? &Z_REF(intern->data)->val : &intern->data); zend_hash_str_update(debug_info, "data", sizeof("data")-1, &zdata); If I need to debug references/refcount it is better to use gdb's pretty-print feature but no var_dump() Le sam. 9 avr. 2022 à 17:51, Glash Gnome <glash.gnome@gmail.com> a écrit :