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
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 :
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
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 :
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_INDIRECTSo 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 :
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