Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:28477 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 88703 invoked by uid 1010); 20 Mar 2007 04:59:14 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 88688 invoked from network); 20 Mar 2007 04:59:14 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 20 Mar 2007 04:59:14 -0000 Authentication-Results: pb1.pair.com header.from=andi@zend.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=andi@zend.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain zend.com designates 63.205.162.114 as permitted sender) X-PHP-List-Original-Sender: andi@zend.com X-Host-Fingerprint: 63.205.162.114 unknown Windows 2000 SP4, XP SP1 Received: from [63.205.162.114] ([63.205.162.114:7456] helo=us-ex1.zend.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id F9/20-17309-02A6FF54 for ; Mon, 19 Mar 2007 23:59:14 -0500 X-MimeOLE: Produced By Microsoft Exchange V6.5 Content-class: urn:content-classes:message MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Date: Mon, 19 Mar 2007 21:59:04 -0700 Message-ID: <698DE66518E7CA45812BD18E807866CE18559A@us-ex1.zend.net> X-MS-Has-Attach: X-MS-TNEF-Correlator: Thread-Topic: [PHP-DEV] PATCH: anonymous functions in PHP Thread-Index: AcdqgyDtJ25arwBoSzKBTNgXICC5CwAKA5xQ References: <86478A67-DCA2-4000-9EF0-DA4338E8389B@omniti.com> <45FDF031.4010508@zend.com> <45FE2312.1050506@zend.com> <45FED6D9.8030307@caedmon.net> <45FEDAE5.2010309@zend.com> <45FEE396.7040905@caedmon.net> <0757BDEA-65F5-4123-B647-060DCA84B4B0@omniti.com> <45FEEF52.1060002@zend.com> <1174336464.24632.110.camel@blobule> <45FEF9A5.4050409@zend.com> <1174338801.24632.124.camel@blobule> <45FEFDCE.7050100@zend.com> <1174339527.24632.129.camel@blobule> <45FF01FE.6070504@zend.com> <698DE66518E7CA45812BD18E807866CE185525@us-ex1.zend.net> To: "Wez Furlong" Cc: "Stas Malyshev" , "Robert Cummings" , "Sean Coates" , Subject: RE: [PHP-DEV] PATCH: anonymous functions in PHP From: andi@zend.com ("Andi Gutmans") Hi Wez, There are various ways to go about implementing this. While reading your email I've had another couple of ideas incl. some funky parameter passing games. All these ideas are legit and have pros/cons but what's most important is actually from a feature point of view, whether we want to do something, and if so what. So I think the questions are: a) Do we want to support another way to create anonymous functions ala create_function, even if it doesn't allow binding to values (closures) from the outer scope (which create_function() supports doing by value; by embedding variables in the string). b) If the answer is yes, then do we want to have a syntax (ala $_SCOPE["i"] or similar)? If so, what does it do? Does it bind to outer variables or does it "embed" the values. If the latter, do we care more about the actual functionality or performance. I hope these questions are clear. I think we need to be very careful when going down this route because some have already alluded that it might be confusing and not quite the PHP spirit, on the other hand there are also valid reasons for doing it. In any case, if we go down this route we should be crystal clear in what behavior we expect and need to feel comfortable that it doesn't have a high wtf-factor associated with it. I need to sleep on it and think about it a bit more tomorrow. Thoughts? Andi > -----Original Message----- > From: Wez Furlong [mailto:wez@omniti.com]=20 > Sent: Monday, March 19, 2007 5:03 PM > To: Andi Gutmans > Cc: Stas Malyshev; Robert Cummings; Sean Coates;=20 > internals@lists.php.net > Subject: Re: [PHP-DEV] PATCH: anonymous functions in PHP >=20 > I've been thinking about this in the car, and it won't quite=20 > work as-is. > Here's a contrived example: >=20 > $funcs =3D array(); > for ($i =3D 0; $i < 10; $i++) { > $funcs[] =3D function() { return $_SCOPE['i']; }; } >=20 > Here I'm assuming that $_SCOPE takes a copy of $i during fixup. > The problem here is that the function is compiled once, so=20 > there is only one place to stash the fixup info for $_SCOPE,=20 > which leaves the results of calling any of the functions in=20 > $funcs undefined. (Just in case it's not clear, the=20 > intention is to create 10 anonymous functions, which return=20 > values 0 through 9). >=20 > There are two ways to solve this, both give the same visible=20 > result to the person writing the code, but one is more invasive. >=20 > The first solution is to have a unique function name=20 > generated on each run through the loop. The function name=20 > would be an alias (ala > FALIAS) to the opcodes, so that there would only be one=20 > version of the compiled opcodes. The based on the=20 > information from $_SCOPE, copies of the variables from the=20 > instantiating scope would be stored along with the oparray,=20 > keyed by the unique function name. >=20 > When the function is called, the name being invoked is used=20 > to locate the saved variables, which are then used to=20 > pre-populate the local scope for the function. $_SCOPE['i']=20 > would have been transposed to simply $i in the op_array. >=20 > So, in psuedo code the above would generate a funcs array like: >=20 > $funcs[0] =3D "__anon_0"; > $funcs[1] =3D "__anon_1"; >=20 > and when the engine goes to invoke __anon_0: >=20 > function __anon_0() { > $_LOCALS =3D get_scope_vars_for('__anon_0'); > return $i; > } >=20 > Where the $_LOCALS line represents the prologue in the ZE=20 > that sets up the local scope for that function "frame". >=20 >=20 > The second possibility would be to make a first-class=20 > callable zval type which stores that information in the=20 > return value from the function declaration. The callable=20 > type would store a pointer to the op_array as well as a hash=20 > table to use to initialize the local scope of the function. =20 > Again, this would be created based on the $_SCOPES fixup=20 > information, and again, $_SCOPES['i'] would be rewritten as=20 > simply $i in the op_array. >=20 > So the funcs array might look like this is var_dump()'d: >=20 > 0 =3D> callable('__anon_0', array('i' =3D> 0)), > 1 =3D> callable('__anon_0', array('i' =3D> 1)), > 2 =3D> callable('__anon_0', array('i' =3D> 2)) >=20 > Adding a type seems cleaner, but obviously requires more work=20 > as the rest of the internals need to understand what to do with it. >=20 >=20 > A third possibility is similar to the second, but a bit less=20 > invasive. Create a callable class type to encapsulate that=20 > information. The rest of the internals would see $funcs[0]=20 > as an object, but the engine would know that calling it will=20 > invoke the appropriate function, prepping the local scope as=20 > described above. >=20 >=20 > --Wez. >=20 >=20 >=20 > On Mar 19, 2007, at 5:59 PM, Andi Gutmans wrote: >=20 > > We could compile the anonymous function at compile-time but leave=20 > > placeholders which need to be "fixed-up" when at run-time=20 > the actual=20 > > closure is created. For this purpose we could introduce a=20 > new magical=20 > > variables $_SCOPE["var"] which references the current $var during=20 > > fixup time. > > So here's an example: > > > > $var =3D php_version(); > > $fancyVer =3D function () { return "PHP $_SCOPE['ver']; }; > > > > So what this does is compile the "anonymous function" at=20 > compile-time,=20 > > but when this line is executed (note, this line of code=20 > should also be=20 > > reached during execution), then we do the fix-up for $_SCOPE=20 > > variables. > > Regular variables remain what they would in=20 > create_function(). Fix-up=20 > > time would be faster than compiling the code. > > > > Thoughts? > > Andi >=20 >=20