Re: [RFC] Closure::call and Function Referencing as Closures
| From: | Andrea Faulds | Date: | Mon, 11 Aug 2014 18:09:24 +0000 |
| Subject: | Re: [RFC] Closure::call and Function Referencing as Closures | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-76435@lists.php.net to get a copy of this message | ||
On 11 Aug 2014, at 08:36, Dmitry Stogov <dmitry@zend.com> wrote:
> Hi Andrea,
>
> Could you measure the performance impact of function referencing.
>
> <?php
> $func = "strlen";
> for ($i = 0; $i < 10000; $i++) {
> $func("hello");
> }
> ?>
>
> vs
>
> <?php
> $func = &strlen;
> for ($i = 0; $i < 10000; $i++) {
> $func("hello");
> }
> ?>
On my machine:
andreas-air:php-src ajf$ time sapi/cli/php ../funcref_a.php
real 0m0.043s
user 0m0.022s
sys 0m0.008s
andreas-air:php-src ajf$ time sapi/cli/php ../funcref_b.php
real 0m0.023s
user 0m0.015s
sys 0m0.006s
I think the reason that function references are faster here is that it only has to do the hash table
lookup once. If you tried to create a reference on each iteration and compared that to just using
the string, then the string would be faster, as no memory needs to be allocated and deallocated for
the closure.
> I don't like the "&" syntax a lot, but I understand that it's a
> compromise between readability and implementation complication.
Right. Myself, I’d prefer to just merge PHP’s namespaces and have $foo = func_name; work, but
that wouldn’t work well and would break a lot of things.
>
> The patch probably misses support for "&self::foo", "&parent::foo",
> "&static::foo”.
Good catch, I’ll try and get that implemented. Actually, I wonder if having &self::foo be
bound to the object using it would be a good idea. While I resisted for &$foo::bar (I don’t
support that syntax anyway), there might be some merit in it after all. If it would bind for you,
you could always remove the binding or change it if it would be a problem.
> It also may be improved using run_time cache (this is not important now).
That’s something I wanted to do (might solve the performance problems with using & on each
iteration), but I’m not sure quite what the right way to implement that is. In particular, what
kind of cache (some sort of hash map?), how to index it (function name? fully-qualified function
name?) and where to put it. I suppose I could just add a zval pointer to zend_function itself, but
that would add eight bytes to every single function, which would add up.
Actually, on a related note: Currently & creates a new closure on each use, and in PHP closures
are compared by identity, not by their value. Perhaps we should change that so it checks for the
same scope, this_ptr and implementation? Having &strlen === &strlen would probably be a good
thing, it’s the more intuitive thing at least. Comparing the this_ptr of the two would be easy,
however I have no idea whether you could compare the two zend_functions and have it work properly.
You can’t just do an == in the C code, as closures embed and modify the zend_function.
--
Andrea Faulds
http://ajf.me/