Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:38348 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 87951 invoked from network); 18 Jun 2008 12:18:05 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 18 Jun 2008 12:18:05 -0000 Authentication-Results: pb1.pair.com smtp.mail=chris_se@gmx.net; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=chris_se@gmx.net; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmx.net designates 213.165.64.20 as permitted sender) X-PHP-List-Original-Sender: chris_se@gmx.net X-Host-Fingerprint: 213.165.64.20 mail.gmx.net Linux 2.6 Received: from [213.165.64.20] ([213.165.64.20:53714] helo=mail.gmx.net) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 09/8D-03518-BFCF8584 for ; Wed, 18 Jun 2008 08:18:04 -0400 Received: (qmail invoked by alias); 18 Jun 2008 12:18:00 -0000 Received: from p54A174D0.dip.t-dialin.net (EHLO chris-se.dyndns.org) [84.161.116.208] by mail.gmx.net (mp043) with SMTP; 18 Jun 2008 14:18:00 +0200 X-Authenticated: #186999 X-Provags-ID: V01U2FsdGVkX1/N5HUsNyPNrJoT5WGzZYDr1qT3X4nMopGUBwjRxO iH4ueZtN8Ak8Z5 Received: from [192.168.0.175] (HSI-KBW-091-089-005-213.hsi2.kabelbw.de [91.89.5.213]) by chris-se.dyndns.org (Postfix) with ESMTP id C679A10678; Wed, 18 Jun 2008 14:07:26 +0200 (CEST) Message-ID: <4858FCC7.5030305@gmx.net> Date: Wed, 18 Jun 2008 14:17:11 +0200 User-Agent: Thunderbird 2.0.0.14 (X11/20080421) MIME-Version: 1.0 To: Andi Gutmans CC: php-dev List References: <4856A547.3080801@gmx.net> <698DE66518E7CA45812BD18E807866CE01B11811@us-ex1.zend.net> In-Reply-To: <698DE66518E7CA45812BD18E807866CE01B11811@us-ex1.zend.net> X-Enigmail-Version: 0.95.6 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Y-GMX-Trusted: 0 Subject: Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP From: chris_se@gmx.net (Christian Seiler) 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