[RFC] Re: [PHP-DEV] __invoke() weirdness

From: Date: Wed, 31 Dec 2008 16:38:18 +0000
Subject: [RFC] Re: [PHP-DEV] __invoke() weirdness
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-42421@lists.php.net to get a copy of this message
Hello David, Tuesday, December 23, 2008, 5:02:43 PM, you wrote: > Hi folks, > I played with __invoke today: > class Curry > { > protected $callable; > protected $args; > public static function create($callable) > { > $curry = new self($callable, array_slice(func_get_args(), 1)); > return $curry; > } > protected function __construct($callable, $args) > { > $this->callable = $callable; > $this->args = $args; > } > public function __invoke() > { > return call_user_func_array($this->callable, array_merge($this- >>args, func_get_args())); > } > } > However, it doesn't work consistently. > This works fine: > $d = new DateTime(); > $getAtom = Curry::create(array($d, 'format'), DATE_ATOM); > echo $getAtom(); > This gives a fatal "Call to undefined method DateTime::getAtom()" > $d = new DateTime(); > $d->getAtom = Curry::create(array($d, 'format'), DATE_ATOM); > echo $d->getAtom(); > Is that intentional? So far it is. Yet I as much as you do not like the inconsistency. So I spend a little bit on providing the following patch that should do what you were looking for. The disadvantage: Calling properties is case sensitive while calling methods isn't. But since this has nothign to do with this patch and the patch only increases consistency I am all for applying it. Comments? Lukas/Johannes? Oh I hate that case insensitivity.... and inconsistency.... > Cheers, > David Best regards, Marcus

Index: Zend/zend_object_handlers.c =================================================================== RCS file: /repository/ZendEngine2/zend_object_handlers.c,v retrieving revision 1.135.2.6.2.22.2.23 diff -u -p -d -r1.135.2.6.2.22.2.23 zend_object_handlers.c --- Zend/zend_object_handlers.c 31 Dec 2008 11:15:32 -0000 1.135.2.6.2.22.2.23 +++ Zend/zend_object_handlers.c 31 Dec 2008 16:26:52 -0000 @@ -791,6 +791,22 @@ static union _zend_function *zend_std_ge zobj = Z_OBJ_P(object); if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) { + if (Z_OBJ_HT_PP(object_ptr)->read_property) { + zval *callable, property, *callable_obj; + zend_class_entry *ce_ptr; + + INIT_PZVAL(&property); + ZVAL_STRINGL(&property, method_name, method_len, 0); + callable = Z_OBJ_HANDLER_PP(object_ptr,read_property)(*object_ptr, &property, BP_VAR_IS TSRMLS_CC); + + if (Z_TYPE_P(callable) == IS_OBJECT + && Z_OBJ_HANDLER_P(callable, get_closure) + && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &ce_ptr, &fbc, &callable_obj TSRMLS_CC) == SUCCESS) { + *object_ptr = callable_obj; + free_alloca(lc_method_name, use_heap); + return fbc; + } + } free_alloca(lc_method_name, use_heap); if (zobj->ce->__call) { zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function)); Index: Zend/tests/closure_033.phpt =================================================================== RCS file: Zend/tests/closure_033.phpt diff -N Zend/tests/closure_033.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/closure_033.phpt 31 Dec 2008 16:26:52 -0000 @@ -0,0 +1,31 @@ +--TEST-- +Closure 033: Calling property Closure +--FILE-- +<?php + +class Test { + public $func; + function __construct() { + $this->func = function() { + echo __METHOD__ . "()\n"; + }; + } +} + +$o = new Test; +ReflectionProperty::export($o, 'func'); +var_dump($o->func); +$f = $o->func; +$f(); +$o->func(); + +?> +===DONE=== +--EXPECTF-- +Property [ <default> public $func ] + +object(Closure)#%d (0) { +} +Test::{closure}() +Test::{closure}() +===DONE=== Index: Zend/tests/closure_034.phpt =================================================================== RCS file: Zend/tests/closure_034.phpt diff -N Zend/tests/closure_034.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/tests/closure_034.phpt 31 Dec 2008 16:26:52 -0000 @@ -0,0 +1,46 @@ +--TEST-- +Closure 034: Calling property supporting __invoke +--FILE-- +<?php + +class Curry +{ + protected $callable; + protected $args; + + public static function create($callable) + { + $curry = new self($callable, array_slice(func_get_args(), 1)); + return $curry; + } + + protected function __construct($callable, $args) + { + $this->callable = $callable; + $this->args = $args; + } + + public function __invoke() + { + return call_user_func_array($this->callable, array_merge($this->args, func_get_args())); + } +} + +$d = new DateTime(); +$getAtom = Curry::create(array($d, 'format'), DATE_ATOM); +var_dump(is_Callable($getAtom)); +var_dump($getAtom()); + +$d = new DateTime(); +$d->getAtom = Curry::create(array($d, 'format'), DATE_ATOM); +var_dump(is_Callable($d->getAtom)); +var_dump($d->getAtom()); + +?> +===DONE=== +--EXPECTF-- +bool(true) +string(%d) "2%d-%d-%dT%d:%d:%d%s" +bool(true) +string(%d) "2%d-%d-%dT%d:%d:%d%s" +===DONE===
« previous php.internals (#42421) next »