Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
On 03.01.2009, at 15:47, Marcus Boerger wrote: However if that is the intention, then something we might want to look into in order to make it easier for those people is to fix something that propbably looks wrong to them. That is binding a closure to a property outside of the scope of the object does not bind the object to the this_ptr as it would in case the assignment is done inside the object scope (a class method). But once again this is somethign to be fixed whether or not we apply the patch. Yes, I was actually going to write another reply to one of your last mails about exactly that. Could that be done? I suppose it would be a good idea. However, what happens if you do the assignment from inside another class? Or is that $this currently not bound in such a case (I suppose it isn't, because that would be pretty confusing, but also pretty interesting in terms of what you can do with it). - David smime.p7s Description: S/MIME cryptographic signature
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Hi, On Sat, 2009-01-03 at 15:47 +0100, Marcus Boerger wrote: I'd say it would be good to concentrate on making 5.3 stable and then see how new features are accepted. If users really demand such a functionality, when using closures for real life development, we can still add it, but that should be done with the time needed to identify side-effects and other consequences, not in a rush during holiday season after a feature freeze has been announced. Stable also means stable features and semantics. And that includes trying to get rid of inconsistencies. ... fixing one inconsistency by introducing new inconsistencies? Like that one: ?php function foo() {} $foo = foo; $foo(); // works $bar = function(){}; // works $o-foo = foo;$o-foo(); // will not work $o-bar = function(){}; $o-bar(); // will work ? And I fear there will be more. Fixing all of them will take time so we can delay 5.3 for another half year or so (... oh and during that time we find another thing to change which will need proper invastigation, too, so we delay again and then we find ) - We should really try to shorten the release cycle, not making it longer. Which, for 5.3, means we should concentrate on fixing bugs, not adding features and change the language. johannes -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Hello Johannes, Friday, January 2, 2009, 7:16:32 PM, you wrote: Hi, On Wed, 2008-12-31 at 17:38 +0100, Marcus Boerger wrote: 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. I thought bout this issue for one day or so, there are three things to consider here: - the language design question - implementation-related things - getting 5.3 out For the first question I have to say that this is a major change to language. Bringing this feature in makes it a mixture of a class-based OO model and JavaScript-like class-less OO model. As I tend to read way more code than I write I, personally, prefer the clearer class based approach. Nonetheless there seems to be large support for this, so let's lake a deeper look: 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. That's one of the symptoms of the underlying problem we're having: In our object implementation methods and properties are kept completely separated. Using properties now like methods will have side effects, one is described above. I found another one today: ?php class A { public $p; public function __construct() { $this-p = function() { echo 1; }; } } class B extends A { private function p() { echo 2; } } $a = new A(); $b = new B(); $a-p(); $b-p(); ? What do you expect? Well, the first call, to $a-p(); works, the second one, to $b-p();, doesn't since where accessing the private method B::p(). $ sapi/cli/php test.php 1 Fatal error: Call to undefined method B::p() in test.php on line 16 Depending on your view on this that result can be correct or wrong, it might even be wrong in different ways, maybe overwriting $a-p with $b-p should be forbidden, maybe it should treat private elements like non-existent ones. The obvious thing is that it feels like the is-a relationship isn't enforced anymore. First, for properties we already have that anyway. Remember you can add properties to object instances at any time. So being able to add methods at any time just reduces one more inconsistency between things. Also since properties follow a mixture of class based and prototype based object model we have to respect prototype semantics for the parts where proptotype model is used. This means when you dynamically add a closure then this is done in the manner of prototype semantics and needs to follow it. Thus with a slightly different code the result is perfectly correct: ?php class A { // public $p; } class B extends A { private function p() { echo 2; } } $a = new A(); $b = new B(); $a-p = function() { echo 1; }; $a-p(); $b-p(); ? So this raises the question what the status quo without the patch is: class Test { public $func; function __construct() { $this-func = function() { echo __METHOD__ . ()\n; }; } private function func() { echo __METHOD__ . ()\n; } } $o = new Test; $f = $o-func; $f();// Test::{closure}() $o-func(); // Error call to private method... So apparently we already have the exact issue at hand and we take precedence in the actual function which in my opinion is a good choice. And this also is exactly the behavior your example with the patch applies shows. To summarize this from my point of view we only get a bit more of consistency. But for people with a JavaScript background we get a lot more. As we now support what they are used to and that actually is a pretty big advantage. However if that is the intention, then something we might want to look into in order to make it easier for those people is to fix something that propbably looks wrong to them. That is binding a closure to a property outside of the scope of the object does not bind the object to the this_ptr as it would in case the assignment is done inside the object scope (a class method). But once again this is somethign to be fixed whether or not we apply the patch. Additionally there are other areas with such conflicts: Reflection (ReflectionMethod doesn't work, ReflectionProperty has no hint it's executable, ...) and other meta-functionality are obvious, others might (and will) be quite hidden. Reflection now has closure support. I guess the only solid way to implement that feature would be by merging the property and method tables into an element table so we reduce such conflicts -- while that's a major engine and language change. Every other approach will have side-effects. That would mean a major change in language and we should not go that route. This leads us to the third consideration: 5.3 is around 1.5 years in development now with lots of new
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Hello David, Friday, January 2, 2009, 8:03:22 AM, you wrote: Marcus, thanks! Why is it Test::{closure}() {closure}() and not Test::{closure}() Test::{closure}() in that test, though? Is it because func1() was there from the Engine's POV after the ctor was called? AFAICT, that's the only difference between the two. No, one is created inside the object instance and one is created outside. So one has a bound $this pointer while the other has not. And the class comes from the bound $this. So if there is no bound $this there is no class and thus the closure becomes a function rather than a method. marcus Cheers, - David On 01.01.2009, at 17:50, Marcus Boerger wrote: Hello David, I added test closure_037.phpt to demonstrate this. marcus Thursday, January 1, 2009, 5:23:08 PM, you wrote: Hi folks, first of all, thank you Marcus for implementing this. Very cool. As for the __get()/__getClosure() stuff, I don't think it's necessary or even an issue. One can never simply do $this- getOverloadPropertyWithInvoke() anyway, because if the prop is not there, a fatal error would be the result. An __isset() call has to be made first along with an (instanceof Closure || method_exists('__invoke')) check in userspace code. Which brings me to the next question - will $method = 'something'; $bar-$method(); work? Not sure if it's necessary; just curious for the most part. - David On 01.01.2009, at 17:06, Marcus Boerger wrote: Hello Hannes, as discussed online. At the moment we should not have any __get() calls during method resolution. The newly updated patch does that now. And I think we are now safe to submit. In the future we could think of adding __getClosure() which would be called to resolve a dynamic closure. But for the moment we do not need it badly and the patch with the increased consistency is good enough. marcus Thursday, January 1, 2009, 4:09:39 PM, you wrote: Hello Hannes, Wednesday, December 31, 2008, 8:33:43 PM, you wrote: On Wed, Dec 31, 2008 at 20:12, Marcus Boerger he...@php.net wrote: Hello Lars, Wednesday, December 31, 2008, 6:59:08 PM, you wrote: Hi Markus, have you measured the performance impact in a class with - say - ten methods? And what to do with __get() and __call()? How are the prioritized in the method resolve order? Translated into user code we now have: public function __zend_call($name, $args) { // Added property lookup if (isset($this-$name)) {// may call __isset $callable = $this-$name; // may call __get Uhmm. I hope I got this wrong as: Well yes, there are no __isset() calls unless you call isset() of course. I have updated the patch and added a test to demonstrate it better (closure_036.phpt). I also added debug information to closures which makes development much easier. The next step is to fix an issue in the engine and then submit unless there is a bigger issue with this. class foo { function __isset() { return true; } function __get() { return hello world; } function __call() { } } $foo = new foo; $foo-foobar(); will first execute __isset(), then __get() and then __call()? That is a major backwards compatibility break, and increases the inconsistency and decreases readability 10times -Hannes Best regards, Marcus Best regards, Marcusze2-callable-properties-5.3-20090101-b.diff.txt-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php Best regards, Marcusze2-callable-properties-5.3-20090101-d.diff.txtze2-callable- properties-6.0-20090101-d.diff.txt-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php Best regards, Marcus -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Hi, On Wed, 2008-12-31 at 17:38 +0100, Marcus Boerger wrote: 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. I thought bout this issue for one day or so, there are three things to consider here: - the language design question - implementation-related things - getting 5.3 out For the first question I have to say that this is a major change to language. Bringing this feature in makes it a mixture of a class-based OO model and JavaScript-like class-less OO model. As I tend to read way more code than I write I, personally, prefer the clearer class based approach. Nonetheless there seems to be large support for this, so let's lake a deeper look: 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. That's one of the symptoms of the underlying problem we're having: In our object implementation methods and properties are kept completely separated. Using properties now like methods will have side effects, one is described above. I found another one today: ?php class A { public $p; public function __construct() { $this-p = function() { echo 1; }; } } class B extends A { private function p() { echo 2; } } $a = new A(); $b = new B(); $a-p(); $b-p(); ? What do you expect? Well, the first call, to $a-p(); works, the second one, to $b-p();, doesn't since where accessing the private method B::p(). $ sapi/cli/php test.php 1 Fatal error: Call to undefined method B::p() in test.php on line 16 Depending on your view on this that result can be correct or wrong, it might even be wrong in different ways, maybe overwriting $a-p with $b-p should be forbidden, maybe it should treat private elements like non-existent ones. The obvious thing is that it feels like the is-a relationship isn't enforced anymore. Additionally there are other areas with such conflicts: Reflection (ReflectionMethod doesn't work, ReflectionProperty has no hint it's executable, ...) and other meta-functionality are obvious, others might (and will) be quite hidden. I guess the only solid way to implement that feature would be by merging the property and method tables into an element table so we reduce such conflicts -- while that's a major engine and language change. Every other approach will have side-effects. This leads us to the third consideration: 5.3 is around 1.5 years in development now with lots of new features. It was announced that we wanted to go to a beta status to get it out soon (release early, release often ...) I'd say it would be good to concentrate on making 5.3 stable and then see how new features are accepted. If users really demand such a functionality, when using closures for real life development, we can still add it, but that should be done with the time needed to identify side-effects and other consequences, not in a rush during holiday season after a feature freeze has been announced. johannes -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Hello Hannes, as discussed online. At the moment we should not have any __get() calls during method resolution. The newly updated patch does that now. And I think we are now safe to submit. In the future we could think of adding __getClosure() which would be called to resolve a dynamic closure. But for the moment we do not need it badly and the patch with the increased consistency is good enough. marcus Thursday, January 1, 2009, 4:09:39 PM, you wrote: Hello Hannes, Wednesday, December 31, 2008, 8:33:43 PM, you wrote: On Wed, Dec 31, 2008 at 20:12, Marcus Boerger he...@php.net wrote: Hello Lars, Wednesday, December 31, 2008, 6:59:08 PM, you wrote: Hi Markus, have you measured the performance impact in a class with - say - ten methods? And what to do with __get() and __call()? How are the prioritized in the method resolve order? Translated into user code we now have: public function __zend_call($name, $args) { // Added property lookup if (isset($this-$name)) {// may call __isset $callable = $this-$name; // may call __get Uhmm. I hope I got this wrong as: Well yes, there are no __isset() calls unless you call isset() of course. I have updated the patch and added a test to demonstrate it better (closure_036.phpt). I also added debug information to closures which makes development much easier. The next step is to fix an issue in the engine and then submit unless there is a bigger issue with this. class foo { function __isset() { return true; } function __get() { return hello world; } function __call() { } } $foo = new foo; $foo-foobar(); will first execute __isset(), then __get() and then __call()? That is a major backwards compatibility break, and increases the inconsistency and decreases readability 10times -Hannes Best regards, Marcus Best regards, MarcusIndex: Zend/zend_closures.c === RCS file: /repository/ZendEngine2/zend_closures.c,v retrieving revision 1.3.2.17 diff -u -p -d -r1.3.2.17 zend_closures.c --- Zend/zend_closures.c31 Dec 2008 11:15:31 - 1.3.2.17 +++ Zend/zend_closures.c1 Jan 2009 16:02:14 - @@ -14,6 +14,7 @@ +--+ | Authors: Christian Seiler chris...@gmx.net | | Dmitry Stogov dmi...@zend.com | + | Marcus Boerger he...@php.net | +--+ */ @@ -22,6 +23,7 @@ #include zend.h #include zend_API.h #include zend_closures.h +#include zend_exceptions.h #include zend_interfaces.h #include zend_objects.h #include zend_objects_API.h @@ -222,6 +224,59 @@ int zend_closure_get_closure(zval *obj, } /* }}} */ +ZEND_API HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */ +{ + zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC); + HashTable *rv; + zval *val; + struct _zend_arg_info *arg_info = closure-func.common.arg_info; + + *is_temp = 1; + ALLOC_HASHTABLE(rv); + zend_hash_init(rv, 1, NULL, ZVAL_PTR_DTOR, 0); + val = closure-this_ptr; + if (!val) { + ALLOC_INIT_ZVAL(val); + } else { + Z_ADDREF_P(val); + } + zend_symtable_update(rv, this, sizeof(this), (void *) val, sizeof(zval *), NULL); + if (closure-func.type == ZEND_USER_FUNCTION closure-func.op_array.static_variables) { + HashTable *static_variables = closure-func.op_array.static_variables; + MAKE_STD_ZVAL(val); + array_init(val); + zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*)); + zend_symtable_update(rv, static, sizeof(static), (void *) val, sizeof(zval *), NULL); + } + + if (arg_info) { + MAKE_STD_ZVAL(val); + array_init(val); + zend_uint i, required = closure-func.common.required_num_args; + for (i = 0; i closure-func.common.num_args; i++) { + char *name, *info; + int name_len, info_len; + if (arg_info-name) { + name_len = zend_spprintf(name, 0, %s$%s, + arg_info-pass_by_reference ? : , + arg_info-name); + } else { + name_len = zend_spprintf(name, 0, %s$param%d, + arg_info-pass_by_reference ? : , + i + 1); + } +
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Hello David, I added test closure_037.phpt to demonstrate this. marcus Thursday, January 1, 2009, 5:23:08 PM, you wrote: Hi folks, first of all, thank you Marcus for implementing this. Very cool. As for the __get()/__getClosure() stuff, I don't think it's necessary or even an issue. One can never simply do $this- getOverloadPropertyWithInvoke() anyway, because if the prop is not there, a fatal error would be the result. An __isset() call has to be made first along with an (instanceof Closure || method_exists('__invoke')) check in userspace code. Which brings me to the next question - will $method = 'something'; $bar-$method(); work? Not sure if it's necessary; just curious for the most part. - David On 01.01.2009, at 17:06, Marcus Boerger wrote: Hello Hannes, as discussed online. At the moment we should not have any __get() calls during method resolution. The newly updated patch does that now. And I think we are now safe to submit. In the future we could think of adding __getClosure() which would be called to resolve a dynamic closure. But for the moment we do not need it badly and the patch with the increased consistency is good enough. marcus Thursday, January 1, 2009, 4:09:39 PM, you wrote: Hello Hannes, Wednesday, December 31, 2008, 8:33:43 PM, you wrote: On Wed, Dec 31, 2008 at 20:12, Marcus Boerger he...@php.net wrote: Hello Lars, Wednesday, December 31, 2008, 6:59:08 PM, you wrote: Hi Markus, have you measured the performance impact in a class with - say - ten methods? And what to do with __get() and __call()? How are the prioritized in the method resolve order? Translated into user code we now have: public function __zend_call($name, $args) { // Added property lookup if (isset($this-$name)) {// may call __isset $callable = $this-$name; // may call __get Uhmm. I hope I got this wrong as: Well yes, there are no __isset() calls unless you call isset() of course. I have updated the patch and added a test to demonstrate it better (closure_036.phpt). I also added debug information to closures which makes development much easier. The next step is to fix an issue in the engine and then submit unless there is a bigger issue with this. class foo { function __isset() { return true; } function __get() { return hello world; } function __call() { } } $foo = new foo; $foo-foobar(); will first execute __isset(), then __get() and then __call()? That is a major backwards compatibility break, and increases the inconsistency and decreases readability 10times -Hannes Best regards, Marcus Best regards, Marcusze2-callable-properties-5.3-20090101-b.diff.txt-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php Best regards, MarcusIndex: 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 - 1.135.2.6.2.22.2.23 +++ Zend/zend_object_handlers.c 1 Jan 2009 16:48:22 - @@ -791,6 +791,24 @@ 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) { + zval **callable, member; + zend_property_info *property_info; + + ZVAL_STRINGL(member, method_name, method_len, 0); + property_info = zend_get_property_info(zobj-ce, member, 1 TSRMLS_CC); + + if (property_info zend_hash_quick_find(zobj-properties, property_info-name, property_info-name_length+1, property_info-h, (void **) callable) == SUCCESS) { + zval *callable_obj; + zend_class_entry *ce_ptr; + + if (Z_TYPE_PP(callable) == IS_OBJECT +Z_OBJ_HANDLER_PP(callable, get_closure) +Z_OBJ_HANDLER_PP(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 - +++ Zend/tests/closure_033.phpt 1 Jan 2009 16:48:23 - @@ -0,0 +1,122 @@ +--TEST-- +Closure 033: var_dump() of
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Marcus, thanks! Why is it Test::{closure}() {closure}() and not Test::{closure}() Test::{closure}() in that test, though? Is it because func1() was there from the Engine's POV after the ctor was called? AFAICT, that's the only difference between the two. Cheers, - David On 01.01.2009, at 17:50, Marcus Boerger wrote: Hello David, I added test closure_037.phpt to demonstrate this. marcus Thursday, January 1, 2009, 5:23:08 PM, you wrote: Hi folks, first of all, thank you Marcus for implementing this. Very cool. As for the __get()/__getClosure() stuff, I don't think it's necessary or even an issue. One can never simply do $this- getOverloadPropertyWithInvoke() anyway, because if the prop is not there, a fatal error would be the result. An __isset() call has to be made first along with an (instanceof Closure || method_exists('__invoke')) check in userspace code. Which brings me to the next question - will $method = 'something'; $bar-$method(); work? Not sure if it's necessary; just curious for the most part. - David On 01.01.2009, at 17:06, Marcus Boerger wrote: Hello Hannes, as discussed online. At the moment we should not have any __get() calls during method resolution. The newly updated patch does that now. And I think we are now safe to submit. In the future we could think of adding __getClosure() which would be called to resolve a dynamic closure. But for the moment we do not need it badly and the patch with the increased consistency is good enough. marcus Thursday, January 1, 2009, 4:09:39 PM, you wrote: Hello Hannes, Wednesday, December 31, 2008, 8:33:43 PM, you wrote: On Wed, Dec 31, 2008 at 20:12, Marcus Boerger he...@php.net wrote: Hello Lars, Wednesday, December 31, 2008, 6:59:08 PM, you wrote: Hi Markus, have you measured the performance impact in a class with - say - ten methods? And what to do with __get() and __call()? How are the prioritized in the method resolve order? Translated into user code we now have: public function __zend_call($name, $args) { // Added property lookup if (isset($this-$name)) {// may call __isset $callable = $this-$name; // may call __get Uhmm. I hope I got this wrong as: Well yes, there are no __isset() calls unless you call isset() of course. I have updated the patch and added a test to demonstrate it better (closure_036.phpt). I also added debug information to closures which makes development much easier. The next step is to fix an issue in the engine and then submit unless there is a bigger issue with this. class foo { function __isset() { return true; } function __get() { return hello world; } function __call() { } } $foo = new foo; $foo-foobar(); will first execute __isset(), then __get() and then __call()? That is a major backwards compatibility break, and increases the inconsistency and decreases readability 10times -Hannes Best regards, Marcus Best regards, Marcusze2-callable-properties-5.3-20090101-b.diff.txt-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php Best regards, Marcusze2-callable-properties-5.3-20090101-d.diff.txtze2-callable- properties-6.0-20090101-d.diff.txt-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
[PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
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, MarcusIndex: 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 - 1.135.2.6.2.22.2.23 +++ Zend/zend_object_handlers.c 31 Dec 2008 16:26:52 - @@ -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 - +++ Zend/tests/closure_033.phpt 31 Dec 2008 16:26:52 - @@ -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 - +++ Zend/tests/closure_034.phpt 31 Dec 2008 16:26:52 - @@ -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
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Marcus Boerger schrieb: Oh I hate that case insensitivity and inconsistency I am all for reducing inconsistencies (and not introducing new ones :-). -- Sebastian Bergmann http://sebastian-bergmann.de/ GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69 -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Hi Markus, have you measured the performance impact in a class with - say - ten methods? And what to do with __get() and __call()? How are the prioritized in the method resolve order? cu, Lars Am Mittwoch, den 31.12.2008, 17:38 +0100 schrieb Marcus Boerger: 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 -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php -- Jabber: l...@strojny.net Weblog: http://usrportage.de signature.asc Description: Dies ist ein digital signierter Nachrichtenteil
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
Hello Lars, Wednesday, December 31, 2008, 6:59:08 PM, you wrote: Hi Markus, have you measured the performance impact in a class with - say - ten methods? And what to do with __get() and __call()? How are the prioritized in the method resolve order? Translated into user code we now have: public function __zend_call($name, $args) { // Added property lookup if (isset($this-$name)) {// may call __isset $callable = $this-$name; // may call __get if (is_callable($callable)) { return call_user_func_array($callable, $args); } } // Original behavior: // Check for __call if (method_exists($this, '__call')) { return $this-__call($name, $args); } // error error_log('Function ' . __CLASS__ . '::' . $name . ' not found'); return NULL; } As to the performance impact. We add one additional hash-lookup per method call on a default class for a non found function. So whenever we would normally call __call we add an additional lookup. cu, Lars Am Mittwoch, den 31.12.2008, 17:38 +0100 schrieb Marcus Boerger: 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 -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php Best regards, Marcus -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] Re: [PHP-DEV] __invoke() weirdness
On Wed, Dec 31, 2008 at 20:12, Marcus Boerger he...@php.net wrote: Hello Lars, Wednesday, December 31, 2008, 6:59:08 PM, you wrote: Hi Markus, have you measured the performance impact in a class with - say - ten methods? And what to do with __get() and __call()? How are the prioritized in the method resolve order? Translated into user code we now have: public function __zend_call($name, $args) { // Added property lookup if (isset($this-$name)) {// may call __isset $callable = $this-$name; // may call __get Uhmm. I hope I got this wrong as: class foo { function __isset() { return true; } function __get() { return hello world; } function __call() { } } $foo = new foo; $foo-foobar(); will first execute __isset(), then __get() and then __call()? That is a major backwards compatibility break, and increases the inconsistency and decreases readability 10times -Hannes -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php