Hi!

1) I am not sure that the current semantics of the "lexical" keyword
is great in all cases. Is the reason why you don't allow by-value
binding so that we don't have to manage more than one lambda instance
per declaration?

First of all: global and static are also used to create references to
other variables (OK, with static they are not visible to the outside,
but nevertheless...) and second because other languages do the same. As
someone corrected me a while ago, even JS uses references, test the
following JavaScript code:

function foo () {
        var x = 5;
        var f = function (n) {
          x += n;
        };
        alert (x);
        f (2);
        alert (x);
}

foo ();

That will yield first 5 and then 7.

2) [minor curiosity - do we want to consider reusing "parent" instead
of "lexical"? I guess that could be confusing but it's not the first
time we reuse a keyword when it's clear that the usage is in two
different places (this is minor and I don't mind much either way
although lexical doesn't mean too much to me).]

Consider this code:

class A {
  public function printSomething ($var) {
    echo "$var\n";
  }
}

class B extends A {
  public function printSomething ($var) {
    $printer = function () {
      parent $var;
      parent::printSomething ('I print: ' . $var);
    };
    $printer ();
  }
}

Yeah, of course, my example is extremely stupid since it could be done
entirely without closures but I really dread the perspective of having
to explain someone the difference between those two lines...

3) I am concerned about binding to classes. First of all we need to
look into more detail what the implications are for bytecode caches
when changing class entries at run-time.

Well, that's the thing: My patch does NOT change classes at runtime, so
that is totally a non-issue. :-)

When creating a lambda function inside a class method, it adds a new
class method for the lambda function at compile time (!). This
compile-time added method has a dynamic name (__compiled_lambda_F_N
where F is the filename and N is a per-file counteŕ). To an opcode cache
processing this class this added method will appear no different than a
normal class method - it can be cached just the same.

Now, upon execution of the code containing the closure, the new opcode
just copies the zend_function structure into a copy, registers that copy
as a resource and returns that resource. As soon as the resource is
garbage collected (or explicitly unset), the op_array copy is destroyed.
No modification of the actual class is done at all - the cache remains
happy.

Just for clarity I have posted a sample output of PHP with my Patch and
VLD active (<153> is the new ZEND_DECLARE_LAMBDA_FUNC opcode that VLD
does not yet know about):

http://www.christian-seiler.de/temp/php-closure-opcodes.txt

Perhaps this helps to understand better how my patch works?

We may want to also consider an option where the lambda binds to the
object and only has public access although I realize that may be
considered by some as too limiting. We'll review these two things in
the coming days.

What do you mean with "binds to the object"?

But if you only want to grant access to public object members: If I
declare a closure inside a class method, from a programmers point of
view I am still within that class - why shouldn't I be able to access
all class properties there? I would find such a limitation quite odd
(and technically unecessary).

Regards,
Christian

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to