PHP5: hook cast_object handler in userspace

php.internals

Cristiano Duarte

23 years ago
Hi internals, Is there a way to hook the cast_object handler in userspace ? What I want is a default "to_string" method called when I do something like: class my_object extends class_with_default_to_string_method { private $value = "Hello"; public function to_string() { //overhiding default to_string wich prints "Object id #n" return $this->value; } } $o = new my_object(); echo $o; or: $o = new xxx(); echo "My stringfied value is=$o"; Thanx, Cristiano Duarte

Cristiano Duarte

23 years ago
Sorry guys,
> $o = new xxx();
should be $o = new my_object(); And if there is a way to hook into zend_standard_class (stdClass) what would make all objects inherit the to_string method, it would be great ! Cristiano Duarte "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem news:20030802224959.58552.qmail@pb1.pair.com...
> Hi internals, > > Is there a way to hook the cast_object handler in userspace ? What I want
is
> a default "to_string" method called when I do something like: > > class my_object extends class_with_default_to_string_method { > private $value = "Hello"; > public function to_string() { //overhiding default to_string wich
prints

Cristiano Duarte

23 years ago
I made a patch to the latest PHP5-CVS wich implements this hook. I think it's useful to make a meaningful object stringfied value. Can anyone verify it and maybe commit it to CVS ? --- zend.c 2003-07-30 14:07:36.000000000 -0300 +++ zend.c.new 2003-08-03 00:27:43.000000000 -0300 @@ -227,10 +227,24 @@ if (expr->value.obj.handlers->cast_object) { TSRMLS_FETCH(); expr->value.obj.handlers->cast_object(expr, expr_copy, IS_STRING, 0 TSRMLS_CC); } else { - expr_copy->value.str.val = (char *) emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG); - expr_copy->value.str.len = sprintf(expr_copy->value.str.val, "Object id #%ld", (long)expr->value.obj.handle); + //call to_string method + zval *fname, *retval; + MAKE_STD_ZVAL(fname); + ZVAL_STRING(fname, "to_string", 1); + TSRMLS_FETCH(); + if (call_user_function_ex(NULL, &expr, fname, &retval, 0, NULL, 0, NULL TSRMLS_CC) == SUCCESS) { + if (Z_TYPE_P(retval) != IS_STRING) { + convert_to_string(retval); + } + ZVAL_STRINGL(expr_copy, Z_STRVAL_P(retval), Z_STRLEN_P(retval), 1); + zval_ptr_dtor(&retval); + } else { + Z_STRVAL_P(expr_copy) = (char *) emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG); + Z_STRLEN_P(expr_copy) = sprintf(Z_STRVAL_P(expr_copy), "Object id #%ld", (long)Z_OBJ_HANDLE_P(expr)); + } + zval_ptr_dtor(&fname); } #if 0 /* FIXME: This might break BC for some people */ expr_copy->value.str.len = sizeof("Object")-1; Thanx, Cristiano Duarte. "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem news:20030802230007.65232.qmail@pb1.pair.com...
> Sorry guys, > > > $o = new xxx(); > should be $o = new my_object(); > > And if there is a way to hook into zend_standard_class (stdClass) what
would
> make all objects inherit the to_string method, it would be great ! > > Cristiano Duarte > > "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem > news:20030802224959.58552.qmail@pb1.pair.com... > > Hi internals, > > > > Is there a way to hook the cast_object handler in userspace ? What I
want

(Marcus Börger)

23 years ago
Hello Cristiano, Sunday, August 3, 2003, 5:33:25 AM, you wrote: CD> I made a patch to the latest PHP5-CVS wich implements this hook. I think CD> it's useful to make a meaningful object stringfied value. CD> Can anyone verify it and maybe commit it to CVS ? CD> --- zend.c 2003-07-30 14:07:36.000000000 -0300 CD> +++ zend.c.new 2003-08-03 00:27:43.000000000 -0300 CD> @@ -227,10 +227,24 @@ CD> if (expr->value.obj.handlers->cast_object) { CD> TSRMLS_FETCH(); CD> expr->value.obj.handlers->cast_object(expr, expr_copy, IS_STRING, 0 CD> TSRMLS_CC); CD> } else { - expr_copy->>value.str.val = (char *) emalloc(sizeof("Object id #")-1 + CD> MAX_LENGTH_OF_LONG); - expr_copy->>value.str.len = sprintf(expr_copy->value.str.val, "Object id #%ld", (long)expr->>value.obj.handle); CD> + //call to_string method CD> + zval *fname, *retval; CD> + MAKE_STD_ZVAL(fname); CD> + ZVAL_STRING(fname, "to_string", 1); CD> + TSRMLS_FETCH(); CD> + if (call_user_function_ex(NULL, &expr, fname, &retval, 0, NULL, 0, CD> NULL TSRMLS_CC) == SUCCESS) { CD> + if (Z_TYPE_P(retval) != IS_STRING) { CD> + convert_to_string(retval); CD> + } CD> + ZVAL_STRINGL(expr_copy, Z_STRVAL_P(retval), Z_STRLEN_P(retval), CD> 1); CD> + zval_ptr_dtor(&retval); CD> + } else { CD> + Z_STRVAL_P(expr_copy) = (char *) CD> emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG); CD> + Z_STRLEN_P(expr_copy) = CD> sprintf(Z_STRVAL_P(expr_copy), "Object id #%ld", CD> (long)Z_OBJ_HANDLE_P(expr)); CD> + } CD> + zval_ptr_dtor(&fname); CD> } CD> #if 0 CD> /* FIXME: This might break BC for some people */ CD> expr_copy->value.str.len = sizeof("Object")-1; CD> Thanx, CD> Cristiano Duarte. CD> "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem CD> news:20030802230007.65232.qmail@pb1.pair.com...
>> Sorry guys, >> >> > $o = new xxx(); >> should be $o = new my_object(); >> >> And if there is a way to hook into zend_standard_class (stdClass) what
CD> would
>> make all objects inherit the to_string method, it would be great ! >> >> Cristiano Duarte >> >> "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem >> news:20030802224959.58552.qmail@pb1.pair.com... >> > Hi internals, >> > >> > Is there a way to hook the cast_object handler in userspace ? What I
CD> want
>> is >> > a default "to_string" method called when I do something like: >> > >> > class my_object extends class_with_default_to_string_method { >> > private $value = "Hello"; >> > public function to_string() { //overhiding default to_string wich >> prints >> > "Object id #n" >> > return $this->value; >> > } >> > } >> > >> > $o = new my_object(); >> > echo $o; >> > >> > or: >> > >> > $o = new xxx(); >> > echo "My stringfied value is=$o"; >> > >> > Thanx, >> > >> > Cristiano Duarte >> > >> > >> >>
The patch doesn't compile (always use confugure --enable-maintainer-zts). Then you assume that every class has a function to_string(), this is not what we want.
-- Best regards, Marcus mailto:helly@php.net

Sterling Hughes

23 years ago
So, being the author of the C-level cast_object(), I thought about exposing this at one time. I decided against it mainly because I needed it for simplexml, and I didn't want an internals decision to be clouded by userspace discussions (how's my whitespace btw?) I really like the idea of PHP having an object interface that is completely transparent. It would be really nice if the language could (preferably via interfaces), provide a way for userspace people to design classes and objects that behave like base types. Is this a bit magical? Yes. But its also the only reason I'd ever use objects. If I need something to map to an external datasource, or an abstract data type, objects are the most powerful container. They allow for more efficiency (fewer function calls), and a more elegant userspace interface. I think it would be really great if the PHP object model contained all the necessary hooks so that something like simplexml could be implemented in userspace. -Sterling Am Son, 2003-08-03 um 04.59 schrieb Marcus Börger:
> Hello Cristiano, > > Sunday, August 3, 2003, 5:33:25 AM, you wrote: > > CD> I made a patch to the latest PHP5-CVS wich implements this hook. I think > CD> it's useful to make a meaningful object stringfied value. > > CD> Can anyone verify it and maybe commit it to CVS ? > > CD> --- zend.c 2003-07-30 14:07:36.000000000 -0300 > CD> +++ zend.c.new 2003-08-03 00:27:43.000000000 -0300 > CD> @@ -227,10 +227,24 @@ > CD> if (expr->value.obj.handlers->cast_object) { > CD> TSRMLS_FETCH(); > CD> expr->value.obj.handlers->cast_object(expr, expr_copy, IS_STRING, 0 > CD> TSRMLS_CC); > CD> } else { > - expr_copy->>value.str.val = (char *) emalloc(sizeof("Object id #")-1 + > CD> MAX_LENGTH_OF_LONG); > - expr_copy->>value.str.len = sprintf(expr_copy->value.str.val, "Object id > #%ld", (long)expr->>value.obj.handle); > CD> + //call to_string method > CD> + zval *fname, *retval; > CD> + MAKE_STD_ZVAL(fname); > CD> + ZVAL_STRING(fname, "to_string", 1); > CD> + TSRMLS_FETCH(); > CD> + if (call_user_function_ex(NULL, &expr, fname, &retval, 0, NULL, 0, > CD> NULL TSRMLS_CC) == SUCCESS) { > CD> + if (Z_TYPE_P(retval) != IS_STRING) { > CD> + convert_to_string(retval); > CD> + } > CD> + ZVAL_STRINGL(expr_copy, Z_STRVAL_P(retval), Z_STRLEN_P(retval), > CD> 1); > CD> + zval_ptr_dtor(&retval); > CD> + } else { > CD> + Z_STRVAL_P(expr_copy) = (char *) > CD> emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG); > CD> + Z_STRLEN_P(expr_copy) = > CD> sprintf(Z_STRVAL_P(expr_copy), "Object id #%ld", > CD> (long)Z_OBJ_HANDLE_P(expr)); > CD> + } > CD> + zval_ptr_dtor(&fname); > CD> } > CD> #if 0 > CD> /* FIXME: This might break BC for some people */ > CD> expr_copy->value.str.len = sizeof("Object")-1; > > > CD> Thanx, > > CD> Cristiano Duarte. > > CD> "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem > CD> news:20030802230007.65232.qmail@pb1.pair.com... > >> Sorry guys, > >> > >> > $o = new xxx(); > >> should be $o = new my_object(); > >> > >> And if there is a way to hook into zend_standard_class (stdClass) what > CD> would > >> make all objects inherit the to_string method, it would be great ! > >> > >> Cristiano Duarte > >> > >> "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem > >> news:20030802224959.58552.qmail@pb1.pair.com... > >> > Hi internals, > >> > > >> > Is there a way to hook the cast_object handler in userspace ? What I > CD> want > >> is > >> > a default "to_string" method called when I do something like: > >> > > >> > class my_object extends class_with_default_to_string_method { > >> > private $value = "Hello"; > >> > public function to_string() { //overhiding default to_string wich > >> prints > >> > "Object id #n" > >> > return $this->value; > >> > } > >> > } > >> > > >> > $o = new my_object(); > >> > echo $o; > >> > > >> > or: > >> > > >> > $o = new xxx(); > >> > echo "My stringfied value is=$o"; > >> > > >> > Thanx, > >> > > >> > Cristiano Duarte > >> > > >> > > >> > >> > > > > > The patch doesn't compile (always use confugure --enable-maintainer-zts). > Then you assume that every class has a function to_string(), this is not what > we want. > > -- > Best regards, > Marcus mailto:helly@php.net
-- UNIX was not designed to stop you from doing stupid things, because that would also stop you from doing clever things. - Doug Gwyn

Cristiano Duarte

23 years ago
>"Marcus BöRger" <marcus.boerger@t-online.de> escreveu na mensagem
news:13610291366.20030803105909@post.rwth-aachen.de...
> > The patch doesn't compile (always use confugure --enable-maintainer-zts). > Then you assume that every class has a function to_string(), this is not
what
> we want. > > -- > Best regards, > Marcus mailto:helly@php.net >
Marcus, 1. I tried to learn how ZE2 works in 5 hours to write this patch... Sorry. I even didn't know how ZE1 works... 2. First I tried with get_method handler but then I didn't know how to call the method with the resulting zend_function union. So I decided to use "call_user_function" directly since if the method doesn't exist FALSE will be returned and the default operation will be done. The __destruct method works the same way... 3. Classes that don't implement the to_string() method will have the default PHP behavior. They don't need to implement to_string(). The __destruct method works the same way... 4.I compiled it with --enable-maintainer-zts and it worked. It compiles with or without --enable-maintainer-zts. I'm using PHP5-200308030330, with the CLI sapi, and now the configure line is: ./configure --enable-debug --enable-maintainer-zts --enable-cli Best regards, Cristiano Duarte PS: the patch file needs to be applied inside ./Zend
> Hello Cristiano, > > Sunday, August 3, 2003, 5:33:25 AM, you wrote: > > CD> I made a patch to the latest PHP5-CVS wich implements this hook. I
think
> CD> it's useful to make a meaningful object stringfied value. > > CD> Can anyone verify it and maybe commit it to CVS ? > > CD> --- zend.c 2003-07-30 14:07:36.000000000 -0300 > CD> +++ zend.c.new 2003-08-03 00:27:43.000000000 -0300 > CD> @@ -227,10 +227,24 @@ > CD> if (expr->value.obj.handlers->cast_object) { > CD> TSRMLS_FETCH(); > CD> expr->value.obj.handlers->cast_object(expr, expr_copy, IS_STRING,
0
> CD> TSRMLS_CC); > CD> } else { > - expr_copy->>value.str.val = (char *) emalloc(sizeof("Object id #")-1
+
> CD> MAX_LENGTH_OF_LONG); > - expr_copy->>value.str.len = sprintf(expr_copy->value.str.val, "Object
id
> #%ld", (long)expr->>value.obj.handle); > CD> + //call to_string method > CD> + zval *fname, *retval; > CD> + MAKE_STD_ZVAL(fname); > CD> + ZVAL_STRING(fname, "to_string", 1); > CD> + TSRMLS_FETCH(); > CD> + if (call_user_function_ex(NULL, &expr, fname, &retval, 0, NULL,
0,
> CD> NULL TSRMLS_CC) == SUCCESS) { > CD> + if (Z_TYPE_P(retval) != IS_STRING) { > CD> + convert_to_string(retval); > CD> + } > CD> + ZVAL_STRINGL(expr_copy, Z_STRVAL_P(retval),
Z_STRLEN_P(retval),

Cristiano Duarte

23 years ago
I read README.SUBMITING_PATCH and attached the patch as specified. Cristiano Duarte "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem news:20030803144736.43225.qmail@pb1.pair.com...
> >"Marcus BöRger" <marcus.boerger@t-online.de> escreveu na mensagem > news:13610291366.20030803105909@post.rwth-aachen.de... > > > > The patch doesn't compile (always use
confugure --enable-maintainer-zts).
> > Then you assume that every class has a function to_string(), this is not > what > > we want. > > > > -- > > Best regards, > > Marcus mailto:helly@php.net > > > > Marcus, > > 1. I tried to learn how ZE2 works in 5 hours to write this patch... Sorry.
I
> even didn't know how ZE1 works... > 2. First I tried with get_method handler but then I didn't know how to
call
> the method with the resulting zend_function union. So I decided to use > "call_user_function" directly since if the method doesn't exist FALSE will > be returned and the default operation will be done. The __destruct method > works the same way... > 3. Classes that don't implement the to_string() method will have the
default
> PHP behavior. They don't need to implement to_string(). The __destruct > method works the same way... > 4.I compiled it with --enable-maintainer-zts and it worked. It compiles
with
> or without --enable-maintainer-zts. > > I'm using PHP5-200308030330, with the CLI sapi, and now the configure line > is: > ./configure --enable-debug --enable-maintainer-zts --enable-cli > > Best regards, > > Cristiano Duarte > > PS: the patch file needs to be applied inside ./Zend > > > > Hello Cristiano, > > > > Sunday, August 3, 2003, 5:33:25 AM, you wrote: > > > > CD> I made a patch to the latest PHP5-CVS wich implements this hook. I > think > > CD> it's useful to make a meaningful object stringfied value. > > > > CD> Can anyone verify it and maybe commit it to CVS ? > > > > CD> --- zend.c 2003-07-30 14:07:36.000000000 -0300 > > CD> +++ zend.c.new 2003-08-03 00:27:43.000000000 -0300 > > CD> @@ -227,10 +227,24 @@ > > CD> if (expr->value.obj.handlers->cast_object) { > > CD> TSRMLS_FETCH(); > > CD> expr->value.obj.handlers->cast_object(expr, expr_copy,
IS_STRING,
> 0 > > CD> TSRMLS_CC); > > CD> } else { > > - expr_copy->>value.str.val = (char *) emalloc(sizeof("Object id
#")-1
> + > > CD> MAX_LENGTH_OF_LONG); > > - expr_copy->>value.str.len = sprintf(expr_copy->value.str.val,
"Object
> id > > #%ld", (long)expr->>value.obj.handle); > > CD> + //call to_string method > > CD> + zval *fname, *retval; > > CD> + MAKE_STD_ZVAL(fname); > > CD> + ZVAL_STRING(fname, "to_string", 1); > > CD> + TSRMLS_FETCH(); > > CD> + if (call_user_function_ex(NULL, &expr, fname, &retval, 0,
NULL,
> 0, > > CD> NULL TSRMLS_CC) == SUCCESS) { > > CD> + if (Z_TYPE_P(retval) != IS_STRING) { > > CD> + convert_to_string(retval); > > CD> + } > > CD> + ZVAL_STRINGL(expr_copy, Z_STRVAL_P(retval), > Z_STRLEN_P(retval), > > CD> 1); > > CD> + zval_ptr_dtor(&retval); > > CD> + } else { > > CD> + Z_STRVAL_P(expr_copy) = (char
*)
> > CD> emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG); > > CD> + Z_STRLEN_P(expr_copy) = > > CD> sprintf(Z_STRVAL_P(expr_copy), "Object id #%ld", > > CD> (long)Z_OBJ_HANDLE_P(expr)); > > CD> + } > > CD> + zval_ptr_dtor(&fname); > > CD> } > > CD> #if 0 > > CD> /* FIXME: This might break BC for some people */ > > CD> expr_copy->value.str.len = sizeof("Object")-1; > > > > > > CD> Thanx, > > > > CD> Cristiano Duarte. > > > > CD> "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem > > CD> news:20030802230007.65232.qmail@pb1.pair.com... > > >> Sorry guys, > > >> > > >> > $o = new xxx(); > > >> should be $o = new my_object(); > > >> > > >> And if there is a way to hook into zend_standard_class (stdClass)
what
> > CD> would > > >> make all objects inherit the to_string method, it would be great ! > > >> > > >> Cristiano Duarte > > >> > > >> "Cristiano Duarte" <cunha17@uol.com.br> escreveu na mensagem > > >> news:20030802224959.58552.qmail@pb1.pair.com... > > >> > Hi internals, > > >> > > > >> > Is there a way to hook the cast_object handler in userspace ? What
I
> > CD> want > > >> is > > >> > a default "to_string" method called when I do something like: > > >> > > > >> > class my_object extends class_with_default_to_string_method { > > >> > private $value = "Hello"; > > >> > public function to_string() { //overhiding default to_string
wich

(Marcus Börger)

23 years ago
Hello Cristiano, Sunday, August 3, 2003, 9:54:55 PM, you wrote: CD> I read README.SUBMITING_PATCH and attached the patch as specified. Not good enough it seems :-( Some comments: - Please always start with tabs, you used spaces to begin lines. - TSRMLS_FETCH() is a variable declaration, so it cannot be used inside a function. - Still you haven't checked whether or not the function to_string() is available.
-- Best regards, Marcus mailto:helly@php.net

Cristiano Duarte

23 years ago
Hi Marcus,
> Not good enough it seems :-(
I'll get there... ;-)
> Some comments: > - Please always start with tabs, you used spaces to begin lines.
done.
> - TSRMLS_FETCH() is a variable declaration, so it cannot be used inside a > function.
If I wipe TSRMLS_FETCH() out, I get this error: /usr/src/zend2/php-src/Zend/zend.c:234: `tsrm_ls' undeclared (first use in this function) So I kept it.
> - Still you haven't checked whether or not the function to_string() is > available.
I checked it with get_method, but I don't know how to call a function (internal, user or overloaded) using the zend_function union. So I check with "get_method" but still call with "call_user_function" when the union has the type=ZEND_USER_FUNCTION. I don't know what to do if type=ZEND_INTERNAL_FUNCTION or type=ZEND_OVERLOADED_FUNCTION, so I just do the default behavior. Plz, if you could help on this... Attached another patch. Cristiano Duarte "Marcus BöRger" <marcus.boerger@t-online.de> escreveu na mensagem news:1639357698.20030803225953@post.rwth-aachen.de...

(Marcus Börger)

23 years ago
Hello Cristiano, Monday, August 4, 2003, 12:10:26 AM, you wrote: CD> Hi Marcus,
>> Not good enough it seems :-(
CD> I'll get there... ;-)
>> Some comments: >> - Please always start with tabs, you used spaces to begin lines.
CD> done. seems like :-)
>> - TSRMLS_FETCH() is a variable declaration, so it cannot be used inside a >> function.
CD> If I wipe TSRMLS_FETCH() out, I get this error: CD> /usr/src/zend2/php-src/Zend/zend.c:234: `tsrm_ls' undeclared (first use in CD> this function) CD> So I kept it. sure, and now you used it corretly.
>> - Still you haven't checked whether or not the function to_string() is >> available.
CD> I checked it with get_method, but I don't know how to call a function CD> (internal, user or overloaded) using the zend_function union. CD> So I check with "get_method" but still call with "call_user_function" when CD> the union has the type=ZEND_USER_FUNCTION. CD> I don't know what to do if type=ZEND_INTERNAL_FUNCTION or CD> type=ZEND_OVERLOADED_FUNCTION, so I just do the default behavior. CD> Plz, if you could help on this... They are simply other types of function just don't care call_user_function_ex() will take care of the differences. In other words you won't need swicth/case.
-- Best regards, Marcus mailto:helly@php.net

Cristiano Duarte

23 years ago
"Marcus BöRger" <marcus.boerger@t-online.de> escreveu na mensagem news:761875207.20030804001846@post.rwth-aachen.de...
> They are simply other types of function just don't care
call_user_function_ex()
> will take care of the differences. In other words you won't need
swicth/case. switch/case removed and patch attached. Is it ok? Should the method be named "to_string()", "tostring()" or "__tostring()" ? Do you commit it to CVS ? Cristiano Duarte