RE: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi Christian, This is a very nice piece of work. Definitely addresses a lot of the issues we have raised in the past. I would like to see such a solution make its way into PHP (see below re: timing). There are some things I'd like to consider: 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? 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).] 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. 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. Re: timing, I think the biggest issue we have right now with PHP 5.3 is that we are not making a clear cut on features. There's always pressure on release managers to include more (I went through the same with 5.0) but at some point you just have to stop at some place or things will never go out as there are always good ideas flowing in. Unfortunately with 5.3 that cut isn't happening and it seems to drag out longer than needed. I prefer having this discussion in the context of a hard date for a beta release after which we'll be especially strict with accepting new features. Each new feature will drag out the beta/RC cycle as they need enough time for testing/feedback/tweaks. Andi -Original Message- From: Christian Seiler [mailto:[EMAIL PROTECTED] Sent: Monday, June 16, 2008 10:39 AM To: php-dev List Subject: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP Hi, As a followup to the discussion in January, I'd like post a revised patch to this list that implements closures and anonymous functions in PHP. INTRODUCTION Closures and lambda functions can make programming much easier in several ways: 1. Lambda functions allow the quick definition of throw-away functions that are not used elsewhere. Imaging for example a piece of code that needs to call preg_replace_callback(). Currently, there are three possibilities to acchieve this: a. Define the callback function elsewhere. This distributes code that belongs together throughout the file and decreases readability. b. Define the callback function in-place (but with a name). In that case one has to use function_exists() to make sure the function is only defined once. Example code: ?php function replace_spaces ($text) { if (!function_exists ('replace_spaces_helper')) { function replace_spaces_helper ($matches) { return str_replace ($matches[1], ' ', 'nbsp;').' '; } } return preg_replace_callback ('/( +) /', 'replace_spaces_helper', $text); } ? Here, the additional if() around the function definition makes the source code difficult to read. c. Use the present create_function() in order to create a function at runtime. This approach has several disadvantages: First of all, syntax highlighting does not work because a string is passed to the function. It also compiles the function at run time and not at compile time so opcode caches can't cache the function. 2. Closures provide a very useful tool in order to make lambda functions even more useful. Just imagine you want to replace 'hello' through 'goodbye' in all elements of an array. PHP provides the array_map() function which accepts a callback. If you don't wan't to hard-code 'hello' and 'goodbye' into your sourcecode, you have only four choices: a. Use create_function(). But then you may only pass literal values (strings, integers, floats) into the function, objects at best as clones (if var_export() allows for it) and resources not at all. And you have to worry about escaping everything correctly. Especially when handling user input this can lead to all sorts of security issues. b. Write a function that uses global variables. This is ugly, non-reentrant and bad style. c. Create an entire class, instantiate it and pass the member function as a callback. This is perhaps the cleanest solution for this problem
[PHP-DEV] Selectable error messages
OK - I've got PHP5.3.0-dev up at the moment in order to test the Firebird stuff, so display_errors is on. I need it on anyway while testing code. The 'problem' I am having is that of cause none of the other PHP stuff I'm using is currently not compatible with PHP5.3 so generates a lot of deprecated warnings in particular. Current one is phpDocumentor which uses is_a() extensively, and has a function to replicate it for backwards compatibility. Short of switching display_errors on and off all the time, how do other people handle this irritation? I could repair phpDocumentor in this case and ignore BC as I will not be running THAT on older version of PHP, and since a run is taking 30 minutes it would be interesting to see if there is any improvement to time. bit the bullet - my copy of phpDocumentor has no is_a() in it -- Lester Caine - G8HFL - Contact - http://lsces.co.uk/lsces/wiki/?page=contact L.S.Caine Electronic Services - http://lsces.co.uk EnquirySolve - http://enquirysolve.com/ Model Engineers Digital Workshop - http://medw.co.uk// Firebird - http://www.firebirdsql.org/index.php -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] Selectable error messages
hi Lester, On Wed, Jun 18, 2008 at 9:14 AM, Lester Caine [EMAIL PROTECTED] wrote: Short of switching display_errors on and off all the time, how do other people handle this irritation? I could repair phpDocumentor in this case and ignore BC as I will not be running THAT on older version of PHP, and since a run is taking 30 minutes it would be interesting to see if there is any improvement to time. Use error_reporting in your php.ini or within your applicaion: error_reporting(E_ALL ^ E_DEPRECATED); Cheers, -- Pierre http://blog.thepimp.net | http://www.libgd.org -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
On Jun 18, 2008, at 2:36 AM, Alexey Zakhlestin wrote: 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? by-reference binding is much closer to other languages symantics. I guess, that was the main reason Christian chose it. by-value may still exist, if people find, that they need it, but only in addition, please. lambda has to reflect changing state of context, to be truly useful In Lua, the language in which I've seen the most of closures and lambda, lexical scoping is handled this way: someVariable1 = asdf; someVariable2 = jkl;; SomeFunction = function() local someVariable2 = 1234; print someVariable1.. ..someVariable2..\n; end print gettype(SomeFunction)..\n; SomeFunction(); someVariable1 = qwer; someVariable2 0987; SomeFunction(); The resulting output of this code fragment would be: function asdf 1234 qwer 1234 The Lua interpreter handles this by resolving variable references as they're made; someVariable1 is looked up in the closure's scope and not found, so the interpreter steps out one scope and looks for it there, repeat as necessary. Once found outside the closure's scope, something similar to the proposed lexical keyword happens. Closures and lexical variables can be nested this way, to the point where a single variable in a sixth-level closure could still have been originally found in the global scope. I'm not sure this would work for PHP, I'm curious what others think. Of course, that fragment does a very poor job of showing off the extreme flexibility of Lua with regards to functions and scoping, but hopefully it illustrates the concept. -- Gwynne, Daughter of the Code This whole world is an asylum for the incurable. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
2008/6/18 Gwynne Raskind [EMAIL PROTECTED]: On Jun 18, 2008, at 2:36 AM, Alexey Zakhlestin wrote: 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? by-reference binding is much closer to other languages symantics. I guess, that was the main reason Christian chose it. by-value may still exist, if people find, that they need it, but only in addition, please. lambda has to reflect changing state of context, to be truly useful In Lua, the language in which I've seen the most of closures and lambda, lexical scoping is handled this way: someVariable1 = asdf; someVariable2 = jkl;; SomeFunction = function() local someVariable2 = 1234; print someVariable1.. ..someVariable2..\n; end print gettype(SomeFunction)..\n; SomeFunction(); someVariable1 = qwer; someVariable2 0987; SomeFunction(); The resulting output of this code fragment would be: function asdf 1234 qwer 1234 The Lua interpreter handles this by resolving variable references as they're made; someVariable1 is looked up in the closure's scope and not found, so the interpreter steps out one scope and looks for it there, repeat as necessary. Once found outside the closure's scope, something similar to the proposed lexical keyword happens. Closures and lexical variables can be nested this way, to the point where a single variable in a sixth-level closure could still have been originally found in the global scope. I'm not sure this would work for PHP, I'm curious what others think. Of course, that fragment does a very poor job of showing off the extreme flexibility of Lua with regards to functions and scoping, but hopefully it illustrates the concept. -- Gwynne, Daughter of the Code This whole world is an asylum for the incurable. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php Is nested scope just the same as namespace in this regard? -- - Richard Quadling Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498r=213474731 Standing on the shoulders of some very clever giants!
Re: [PHP-DEV] FastArray, great addition
On 16.06.2008 14:28, Pierre Joye wrote: My only wish is to actually respect the informal decision we took a while back, to do not use fast, improved, better or similar wording in function or extension names. What's about naming it CArray or something similar? To reflect what it is, it is not a fast(er) hash table like our current array, it is a C-like array. I can live with any name, so feel free to choose whatever you like most. offtopic Though I'd like to be able to cast these arrays to PHP's arrays and we need to implement get_properties() handler for that. If there are no objections, I'll commit my patch when I get back home (30th of June). -- Wbr, Antony Dovgal -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi! - I am a little confused about the OOP interaction. How does a function become a public method of the class? To clarify: the public method ist just the internal representation of the lambda function and has *nothing* to do with the semantics of calling the lambda itself. The method only means that the lambda function defined inside another method can access the class members and public only means that the lambda function can still be called from outside the class. If one knew how to access it, which it seems is not possible/feasible for user-space code. No, that's not what I meant. The engine uses the following internal trick: a) Upon copmilation, my patch simply adds the lambdas as normal functions to the function table with an automatically generated unique (!) name. If it happens to be defined within a class method, the function will be added as a public final method to that class. b) That added function is not directly callable due to checks of a flag in the internal structure of that function. c) At the place of the function definition the compiler leaves an opcode grab function $generatedname and make a closure out of it. This opcode then looks up the generated lambda function, copies the function structure, saves the bound variables in that structure and returns the copied structure as a resource. d) Normally, when a function is called, the name is looked up in the function table. The function structure that is retrieved from there is then used to execute the function. Since a lambda resource is already a function structure, there is no necessity to look up anything in the function table but the function structure can be directly passed on to the executor. Please note step d): The closure functionality only changes the *lookup* of the function - so instead of getting the function structure from a hash table lookup I get the function structure by retrieving it from the resource. But *after* the lookup of a class method there are checks for the access protection of that method. So these access protection checks also apply to closures that were called. If a lambda function was not declared public, it could not be used outside of the class it was defined in. Perhaps this makes it clearer? I see. It would be great if you could update the RFC with this information so that it's clearer. Done: http://wiki.php.net/rfc/closures Two other questions that just occurred to me: 1) What is the interaction with namespaces, if any? Are lambdas as implemented here ignorant of namespace, or do they take the namespace where they are lexically defined? My patch itself is namespace-ignorant, but the net result is not: a) The generated internal function names do not contain the current namespace name, but since namespace names in function names are only used for lookup if you want to call the function. And calling lambdas by name (!) directly doesn't work anyway (is not supposed to work) so this poses no problem. b) The code *inside* the closure is namespace-aware because the information of which namespace is used is added at compile time. Either the name lookup is done entirely at compile time or the current compiler namespace is automatically added to all runtime lookup calls (this is already the case with current code). So the information which namespace a function resides in is currently *irrelevant* at runtime when calling other functions. For (b) let me make two examples: Suppose you have the following code: namespace Foo; function baz () { return Hello World!\n; } function bar () { return function () { echo baz (); }; } and in another file: $lambda = Foo::bar (); $lambda (); This will - as expected - print Hello World!\n. The reason is that the compiler upon arriving at the baz() function call inside the closure already looks up the function in the function table directly (it knows the current namespace) - and simply creates a series of opcodes that will call the function with the name Foo::baz (the lookup is already done at compile time). Consider this other code: foo-bar.php: namespace Foo; function bar () { return function () { echo baz (); }; } foo-baz.php: namespace Foo; function baz () { return Hello World!\n; } baz.php: function baz () { return PHP!\n; } test1.php: require 'foo-bar.php'; require 'foo-baz.php'; $lambda = Foo::bar (); $lambda (); test2.php: require 'foo-bar.php'; require 'baz.php'; $lambda = Foo::bar (); $lambda (); Running test1.php yields Hello World! whereas running test2.php yields PHP!. Why is this? Because when the compiler reaches the baz () function call in the closure, it cannot find the function so it cannot determine whether it's a function in global or in namespace scope. So it will simply add a series of opcodes that say try Foo::bar and if that does not exist try bar. Here again, Foo:: is added by
Re: [PHP-DEV] Selectable error messages
Lester Caine wrote: Short of switching display_errors on and off all the time, how do other people handle this irritation? I don't have experiences with E_DEPRECATED, but for E_STRICT we use a custom error handler to surpress strict errors in external libraries. Not all E_STRICT errors can be caught in this way, especially not if you are using an opcode cache. Our error handler looks like this, perhaps you can do something similar for E_DEPRECATED.: if (!($errorNumber error_reporting()) || $errorNumber == E_STRICT (strpos($fileName, '/pear/') !== false || strpos($fileName, '/smarty/') !== false || preg_match('/^Non-static method (DB|HTTP|Mail_RFC822|PEAR)::/', $message))) { if ($errorNumber (E_ERROR | E_RECOVERABLE_ERROR | E_USER_ERROR)) { exit; } return; } // Show error message etc. Christian -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
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
Re: [PHP-DEV] FastArray, great addition
On 6/18/08, Antony Dovgal [EMAIL PROTECTED] wrote: Though I'd like to be able to cast these arrays to PHP's arrays and we need to implement get_properties() handler for that. If there are no objections, I'll commit my patch when I get back home (30th of June). 2-way conversion would be perfect ;) -- Alexey Zakhlestin http://blog.milkfarmsoft.com/ -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi! The Lua interpreter handles this by resolving variable references as they're made; someVariable1 is looked up in the closure's scope and not found, so the interpreter steps out one scope and looks for it You may get into a problem here - creator's scope may not exist when you execute the closure, and using caller's scope would be very unexpected - usually closures are intended to capture part of creating environment, not calling environment. It would also impose serious penalty if you just use undefined variable - you'd have to go through whole stack up to the top. there, repeat as necessary. Once found outside the closure's scope, something similar to the proposed lexical keyword happens. Closures lexical in the proposal binds to creator's scope, not caller's scope, as I understood. Anyway, binding to caller's immediate scope doesn't seem that useful since you could just pass it as a parameter when calling. -- Stanislav Malyshev, Zend Software Architect [EMAIL PROTECTED] http://www.zend.com/ (408)253-8829 MSN: [EMAIL PROTECTED] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi! First: My patch is quite non-intrusive, it only adds things in a few places (new opcode, a few checks). If you only look at the non-generated I think it falls into famous last words category. While I did not have time yet to look into the patch in the detail, I have hard time to believe patch creating wholly new concept in PHP, new opcodes, etc. would have zero impact. You have to consider at least the following: tests, documentation, how lexical interacts with other references (global? static? just variable passed by-ref?), how closure interacts with various reflection capabilities, how it works with bytecode caches, what happens with lifetimes of the variables saved in closures - especially implicit ones like $this, etc., etc. I know these questions can be answered, and maybe even easily answered, but I think they have to be answered without pressure of 5.3 release and commitment to the fixed API hanging over us. I understand your urge to have it inside ASAP - if you didn't want it, you'd not gone through this effort to create it :) However, I still think we better not make 5.3 dependent on yet another new feature. As for adoption - I think it would take a long time for off-the-shelf libraries and mainstream users to use this anyway, and for the hackers among us it will be available in development version pretty soon after 5.3. I think if we would decide that every new feature anybody can think about should enter into 5.3 because it will be harder to adopt it otherwise, we'd never release 5.3 at all - look at the RFCs, we have a bunch of ideas already, and I'm sure there will be more. We need to release some time - what happened to that release often thing? Please do not consider this to be opinion about (or against) the patch - I think the idea is good and from preliminary glance the implementation is very nice too, but IMHO we just can not have everything in one release. -- Stanislav Malyshev, Zend Software Architect [EMAIL PROTECTED] http://www.zend.com/ (408)253-8829 MSN: [EMAIL PROTECTED] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hello, I am curious if is_callable will be able to detect these? Or do we need a is_lamba, or is_function or something. You may have mentioned it but reading through I did not notice. I am only curious how to know when someone passed me one of these. Maybe a type hint would be nice too but that is a different conversation I guess. -Chris
Re: [PHP-DEV] FastArray, great addition
On 18.06.2008 16:40, Alexey Zakhlestin wrote: On 6/18/08, Antony Dovgal [EMAIL PROTECTED] wrote: Though I'd like to be able to cast these arrays to PHP's arrays and we need to implement get_properties() handler for that. If there are no objections, I'll commit my patch when I get back home (30th of June). 2-way conversion would be perfect ;) There is no way to cast an array to an object of certain class, but it should not be a problem to add a function to convert array to fastarray. Want to make a patch yourself? Should be pretty easy to do, just don't forget to throw an exception on string key. -- Wbr, Antony Dovgal -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] FastArray, great addition
On 6/18/08, Antony Dovgal [EMAIL PROTECTED] wrote: 2-way conversion would be perfect ;) There is no way to cast an array to an object of certain class, but it should not be a problem to add a function to convert array to fastarray. Want to make a patch yourself? Should be pretty easy to do, just don't forget to throw an exception on string key. I will give it a try -- Alexey Zakhlestin http://blog.milkfarmsoft.com/ -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] FastArray, great addition
Hello, On Wed, Jun 18, 2008 at 4:47 PM, Antony Dovgal [EMAIL PROTECTED] wrote: On 18.06.2008 16:40, Alexey Zakhlestin wrote: On 6/18/08, Antony Dovgal [EMAIL PROTECTED] wrote: Though I'd like to be able to cast these arrays to PHP's arrays and we need to implement get_properties() handler for that. If there are no objections, I'll commit my patch when I get back home (30th of June). 2-way conversion would be perfect ;) There is no way to cast an array to an object of certain class, but it should not be a problem to add a function to convert array to fastarray. Want to make a patch yourself? Should be pretty easy to do, just don't forget to throw an exception on string key. I'll take care of it (both conversions actually) Regards -- Wbr, Antony Dovgal -- Etienne Kneuss http://www.colder.ch Men never do evil so completely and cheerfully as when they do it from a religious conviction. -- Pascal -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
On Jun 18, 2008, at 11:01 AM, Stanislav Malyshev wrote: The Lua interpreter handles this by resolving variable references as they're made; someVariable1 is looked up in the closure's scope and not found, so the interpreter steps out one scope and looks for it You may get into a problem here - creator's scope may not exist when you execute the closure, and using caller's scope would be very unexpected - usually closures are intended to capture part of creating environment, not calling environment. It would also impose serious penalty if you just use undefined variable - you'd have to go through whole stack up to the top. This lookup happens at the time the closure is first declared, and the value is stored for later use by the closure; the calling scope doesn't need to exist anymore. The problem with going to the top of the stack is an issue, though; the Lua interpreter's idea of scope is rather different from PHPs, and it's not nearly the same penalty there. -- Gwynne, Daughter of the Code This whole world is an asylum for the incurable. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi, [I'm going to collect here a bit:] Stanislav Malyshev wrote: lexical in the proposal binds to creator's scope, not caller's scope, as I understood. Anyway, binding to caller's immediate scope doesn't seem that useful since you could just pass it as a parameter when calling. Correct and I completely agree. Chris Stockton wrote: I am curious if is_callable will be able to detect these? Yes, as is call_user_func able to call them. (But as I was verifying that I saw that there was a tiny bug in the code that makes sure the internal names are not used directly, I will fix that.) Richard Quadling wrote: [JS Example] I'm not sure I would say that there is a reference used there. I'm no expert, but x, f() and n are all working like normal variables with x having to look outside of f(). Unless I'm getting confused with pass by reference. Yes, shure, ok, it's not a reference in the classical sense BUT the effect is the same: A change INSIDE the closure changes the variable outside. The only useful way of doing that in PHP without rewriting the complete engine is using references - and such things are *already* done via references - namely global variables: If you import a variable via $global, in reality you are creating a reference to the actual global variable - global $foo is actually more or less the same as $foo = $_GLOBALS['foo']. Regards, Christian -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi! This lookup happens at the time the closure is first declared, and the value is stored for later use by the closure; the calling scope doesn't This would work for $var, but what about $$var and various other ways of indirect variable access? -- Stanislav Malyshev, Zend Software Architect [EMAIL PROTECTED] http://www.zend.com/ (408)253-8829 MSN: [EMAIL PROTECTED] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] getting current request's response code
Hi! Any interest in the attached patch? It introduces a headers_response_code() function which returns I see no problem with it. Just don't forget to add docs and test if you add it :) -- Stanislav Malyshev, Zend Software Architect [EMAIL PROTECTED] http://www.zend.com/ (408)253-8829 MSN: [EMAIL PROTECTED] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
RE: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi Christian, Thanks for the clarifications. This helped a lot and makes me feel very confident about this implementation. I think this is a very strong proposal. A few additional things I thought about while taking a closer look: - You mention global and static as examples of how we do things today. They are actually not good examples because the binding by reference which they do has been a real pain over the years. This is why we introduced the $GLOBALS[] array so that you could also assign by reference ($GLOBALS[foo] = $var). Now that I think of this example I'd actually prefer to see $LEXICALS[] or something similar to access variables then go with the broken global/static behavior. This will bite us and people will complain... In general, I always recommend to people to keep away from global and go with $GLOBALS[]. - Minor implementation suggestion: I am not sure we need those flags for closures and have those if() statements before function calls. We took the same approach with other obfuscated functions/methods/variables. If the developer *really* wants to cheat the engine and assemble an obfuscated name then he can. It's like doing the following in C: ((fun(*)()) 0x454544)(). I say, be my guest. It just simplifies implementation a bit. No biggy but consistent with the rest of PHP. - Please check eval(). I assume it will bind to global scope but let's just make sure what happens esp. when it's called from within a method... - In PHP 5, object storage is resources done right. I don't think we should be using the resource infrastructure for this implementation and would prefer to use the object one. It's better. I suggest to take a look at it. Will also look into byte code cache implementation issues incl. performance pieces but it looks like there shouldn't be any show stoppers here but I want to verify. Thanks again for your hard work! Andi
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi! by reference ($GLOBALS[foo] = $var). Now that I think of this example I'd actually prefer to see $LEXICALS[] or something similar The problem here might be that if we do something like $LEX[$foo] in runtime, we don't know which parts of parent's scope we need to preserve. While I like the syntax, it may not work this way. Which brings me to another point - how bad would it be if closure's lifetime would be limited to parent's lifetime? Of course, this would limit some tricks, but would allow some other - like this direct access to parent's scope. - Minor implementation suggestion: I am not sure we need those flags for closures and have those if() statements before function calls. We In any case I think we don't need to waste 2 bytes (or more with alignment) on something that's essentially 2 bits. I know it's nitpicking, but every little bit helps :) Of course, if we drop the flags the point is moot. -- Stanislav Malyshev, Zend Software Architect [EMAIL PROTECTED] http://www.zend.com/ (408)253-8829 MSN: [EMAIL PROTECTED] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
On 6/18/08, Stanislav Malyshev [EMAIL PROTECTED] wrote: Which brings me to another point - how bad would it be if closure's lifetime would be limited to parent's lifetime? Of course, this would limit some tricks, but would allow some other - like this direct access to parent's scope. that would be seriously bad, because it will eliminate possibility of lambda-generating functions -- Alexey Zakhlestin http://blog.milkfarmsoft.com/ -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] [RFC] Closures and lambda functions in PHP
Hi Andi, Hi Stanislav, - You mention global and static as examples of how we do things today. They are actually not good examples because the binding by reference which they do has been a real pain over the years. This is why we introduced the $GLOBALS[] array so that you could also assign by reference ($GLOBALS[foo] = $var). Now that I think of this example I'd actually prefer to see $LEXICALS[] or something similar to access variables then go with the broken global/static behavior. This will bite us and people will complain... In general, I always recommend to people to keep away from global and go with $GLOBALS[]. The problem here might be that if we do something like $LEX[$foo] in runtime, we don't know which parts of parent's scope we need to preserve. While I like the syntax, it may not work this way. Yes, that's the point. 'lexical $foo' does two things (instead of global simply doing one thing): a) At compile time (!) remember the name of the variable specified in an internal list assigned to the function. Example: function () { lexical $data, $i; } This will cause op_array-lexical_names to be the list data, i. b) At run time, the lexical keyword creates a reference to the lexical variables that are stored in op_array-lexical_variables (just as global does with global scope) The op_array-lexical_variables itself is filled in the new opcode which is executed upon *assignment* (read: creation) of the closure. It's essentially a for loop that goes through op_array-lexical_names and adds a reference from the current symbol table to the op_array-lexical_variables table. So, to make an example (with line numbers for reference): 1 $data = foo; 2 $i = 4; 3 $func = function () { 4 lexical $data, $i; 5 return array ($data, $i); 6 }; 7 8 $func (); Step 1 (Line 4 at compile time): op_array-lexical_names is set to data, i. Step 2 (Line 3 at run time): The ZEND_DECLARE_LAMBDA_FUNC opcode is executed, it creates a copy of the op_array to store in the return value, in the copy it initializes the hash table op_array-lexical_variables and then creates two new variables in op_array-lexical_variables which are references to the current scope varialbes $data and $i: +---+ +-+ | lex_variables | | EG(active_symbol_table) | +---+ ref +-+ | data--|--|- data | | i --|--|- i | | | | func | | | | ... | +---+ +-+ Step 3 (Line 8 at run time): The closure is executed. Step 4 (Line 4 at run time): The lexical keyword retrieves the $data and $i variables from op_array-lexical_variables and adds a reference to them: +-+ +---+ +-+ | EG(active_symbol_table) | | lex_variables | | parent s.t. | +-+ +---+ +-+ | data|--|- data ---|--|- data | | i |--|- i---|--|- i | | | | | | func | | | | | | ... | +-+ +---+ +-+ Btw: The grammar for lexical_variable contains only T_VARIABLE (and not ${...} etc.) on purpose - to be sure the name can be extracted at compile time. (Just as a clarification how the patch internally works.) Frankly, I don't really see a problem with using references. It fits into what's already there in PHP and it assures that closures have the necessary properties to make them useful. Which brings me to another point - how bad would it be if closure's lifetime would be limited to parent's lifetime? Of course, this would limit some tricks, but would allow some other - like this direct access to parent's scope. That trick would actually completely destroy the concept of closures: The idea behind closures is that the lexical scope during *creation* of the closure is saved. If you say I want direct access via $LEXICALS then the lexical scope during the *execution* of the closure will be used (yeah sure, the scope will be the scope during the creation of the closure but the *state* of that scope will be the scope during execution and not creation - unbinding variables after defining the closure (and therefore for example loops) will not be possible at that point). Furthermore, the idea that the closure lives longer than the scope in which it was declared is one of the other most basic ideas behind closures. Also, consider this code: function foo () { $lambda = function () { echo Hello World!\n; }; $lambda
[PHP-DEV] [PATCH] unix path separators in spl
Hi all, In Phar we have an internal Windows-only function named phar_unixify_path_separators(), which is needed because Phar is intended to be used with web apps. Phar inherits from SPL, which currently uses the system-specific DEFAULT_SLASH when returning directory paths. This isn't actually a problem in Phar (at least, as far as I'm aware) but it does look... well, untidy. The attached patch implements spl_unixify_path_separators(). If it's accepted, we can probably kill the version in Phar and rely on the definition in SPL. However I'm concerned that some other extension might be relying on SPL's current behaviour, unlikely tho' it may seem. I haven't found any change in behaviour running the test suite for: ext/spl, ext/phar, ext/standard/array, ext/simplexml. I haven't tested: ext/pdo, ext/sqlite, ext/mysqli or pecl/spl_types, and I'm not certain if there should be any more on that list. If you find/can see any problems with this change at all, pls adv. If there are no objections, I plan to commit at the end of this week. Thanks, - Steph Index: ext/spl/spl_directory.c === RCS file: /repository/php-src/ext/spl/spl_directory.c,v retrieving revision 1.45.2.27.2.23.2.22 diff -u -r1.45.2.27.2.23.2.22 spl_directory.c --- ext/spl/spl_directory.c 18 Jun 2008 10:05:29 - 1.45.2.27.2.23.2.22 +++ ext/spl/spl_directory.c 18 Jun 2008 17:16:39 - @@ -185,6 +185,9 @@ intern-file_name_len = spprintf(intern-file_name, 0, %s%c%s, spl_filesystem_object_get_path(intern, NULL TSRMLS_CC), DEFAULT_SLASH, intern-u.dir.entry.d_name); +#ifdef PHP_WIN32 + spl_unixify_path_separators(intern-file_name, intern-file_name_len); +#endif break; } } @@ -1196,6 +1199,9 @@ subdir-u.dir.sub_path_len = strlen(intern-u.dir.entry.d_name); subdir-u.dir.sub_path = estrndup(intern-u.dir.entry.d_name, subdir-u.dir.sub_path_len); } +#ifdef PHP_WIN32 + spl_unixify_path_separators(intern-u.dir.sub_path, intern-u.dir.sub_path_len); +#endif subdir-info_class = intern-info_class; subdir-file_class = intern-file_class; subdir-oth = intern-oth; @@ -1227,6 +1233,9 @@ if (intern-u.dir.sub_path) { len = spprintf(sub_name, 0, %s%c%s, intern-u.dir.sub_path, DEFAULT_SLASH, intern-u.dir.entry.d_name); +#ifdef PHP_WIN32 + spl_unixify_path_separators(sub_name, len); +#endif RETURN_STRINGL(sub_name, len, 0); } else { RETURN_STRING(intern-u.dir.entry.d_name, 1); Index: ext/spl/spl_directory.h === RCS file: /repository/php-src/ext/spl/spl_directory.h,v retrieving revision 1.12.2.5.2.4.2.10 diff -u -r1.12.2.5.2.4.2.10 spl_directory.h --- ext/spl/spl_directory.h 20 May 2008 21:46:50 - 1.12.2.5.2.4.2.10 +++ ext/spl/spl_directory.h 18 Jun 2008 17:10:18 - @@ -112,6 +112,20 @@ return (spl_filesystem_object*)((char*)it - XtOffsetOf(spl_filesystem_object, it)); } +#ifdef PHP_WIN32 +static inline void spl_unixify_path_separators(char *path, int path_len) +{ + char *s; + + /* unixify win paths */ + for (s = path; s - path path_len; ++s) { + if (*s == '\\') { + *s = '/'; + } + } +} +#endif + #define SPL_FILE_OBJECT_DROP_NEW_LINE 0x0001 /* drop new lines */ #define SPL_FILE_OBJECT_READ_AHEAD 0x0002 /* read on rewind/next */ #define SPL_FILE_OBJECT_SKIP_EMPTY 0x0006 /* skip empty lines */ -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] make it possible to skip very slow tests
Hi! +$environment['EXEMPT_SLOW_TESTS'] = 1; Maybe SKIP_SLOW_TESTS? If it's checked in skip section... :) Otherwise - good idea! -- Stanislav Malyshev, Zend Software Architect [EMAIL PROTECTED] http://www.zend.com/ (408)253-8829 MSN: [EMAIL PROTECTED] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] make it possible to skip very slow tests
Hey Steph; On Jun 18, 2008, at 3:37 PM, Steph Fox wrote: I'm using this locally because two of our tests take over 10 minutes each to run on my laptop, and I run the relevant bits of test suite every time I make a change. All it does is adds another option, -x, to run-tests.php. This sets an environmental variable which can then be checked for in the SKIPIF section of very slow-running tests. How do you specify that test A is slow? Is there a certain skipif message you include, or...? -T -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] Strict type hints (parameter and return value)
In mathematic, equal meen the same value AND the same nature. The follow fact could be frustrating : Code : ? php echo 'you must understand than 1 + 1 = 2' ? Output : you must understand than 2 = 2 - Original Message - From: Stanislav Malyshev [EMAIL PROTECTED] To: Chris Stockton [EMAIL PROTECTED] Cc: internals@lists.php.net Sent: Monday, June 16, 2008 11:02 PM Subject: Re: [PHP-DEV] [RFC] Strict type hints (parameter and return value) Hi! Maybe we should stop using the 1 and '1' argument, yes, they can be Maybe not, while there are people that fail to understand it. Here: But try to remember, 1 !== '1' and PHP is not an end all language, often we have to communicate to strictly type systems, we need to be positive So you just ignored the special cases part. Yes, if you have special case where you interface with very brain-dead strictly typed system that absolutely can't understand that '1' and 1 is the same - then you need to _convert_. So how failing when you get '1' instead of 1 helps you? You'd need _conversion_, not _failure_ - and if you write strictly-typed API, you'd move the conversion responsibility to the user, instead of having it where it belongs - in the API. That's *exactly* why I see strict typing in PHP so dangerous - it promotes lazyness and sloppiness in API writing, and those APIs will be a nightmare to use, since they would bomb out on slightest disagreement about internal engine types, which the API user shouldn't care about at all. What happened with be liberal at what you accept? In strict compiled languages, the compiler and IDE will guide you through this, in PHP you'd just have it explode in your face in production. How this is good for anybody? -- Stanislav Malyshev, Zend Software Architect [EMAIL PROTECTED] http://www.zend.com/ (408)253-8829 MSN: [EMAIL PROTECTED] -- 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
Re: [PHP-DEV] deprecation status of $str{42} versus $str[42]
Maybe TextIterator can be backported from HEAD, because it allows for just that. foreach (new TextIterator($str) as $c) { ... } Arvids Godjuks wrote: 2008/6/16 Edward Z. Yang [EMAIL PROTECTED]: PHP userland code may not treat strings as first class arrays, but that's certainly how they are represented internally. Anyway, it would be neat if we could get that foreach syntax to work. I get sick of for($i = 0, $c = strlen($str); $i $c; $i++) very quickly. Totaly agree, the best example from the whole thread -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] deprecation status of $str{42} versus $str[42]
Hi! Maybe TextIterator can be backported from HEAD, because it allows for just that. foreach (new TextIterator($str) as $c) { ... } That'd be a nice addition to intl extension, too - if we implement all functionality. Any volonteers? :) Problem there would be that it would be somewhat slower - characters would have to be converted from Unicode to UTF-8 on each cycle - if we use ICU iterators (not necessary for simple cases I guess). But having it in 5.x would help some people, I guess. -- Stanislav Malyshev, Zend Software Architect [EMAIL PROTECTED] http://www.zend.com/ (408)253-8829 MSN: [EMAIL PROTECTED] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] deprecation status of $str{42} versus $str[42]
Andrei Zmievski wrote: Maybe TextIterator can be backported from HEAD, because it allows for just that. foreach (new TextIterator($str) as $c) { ... } IIRC, TextIterator is specifically designed for Unicode, letting you iterate over codepoints, combining sequences, characters, words, etc. So making it do all that would only make sense with intl, and even then not really (as Stanislav points out performance-wise). What I was suggesting was a shortcut to iterating over binary data; i.e. byte by byte. -- Edward Z. YangGnuPG: 0x869C48DA HTML Purifier http://htmlpurifier.org Anti-XSS Filter [[ 3FA8 E9A9 7385 B691 A6FC B3CB A933 BE7D 869C 48DA ]] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [RFC] Strict type hints (parameter and return value)
Fabrice VIGNALS wrote: In mathematic, equal meen the same value AND the same nature. The follow fact could be frustrating : Usually, context is good enough to disambiguate between the cases. The most prevalent convention in programming languages is = is assignment, and == is comparison (PHP adds === only because of its type-juggling system). Other languages have = as comparison, and := as assignment. Donald Knuth uses = as comparison, and a left arrow (-) for assignment. -- Edward Z. YangGnuPG: 0x869C48DA HTML Purifier http://htmlpurifier.org Anti-XSS Filter [[ 3FA8 E9A9 7385 B691 A6FC B3CB A933 BE7D 869C 48DA ]] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] deprecation status of $str{42} versus $str[42]
Yes, and we can have TextIterator work on binary strings as well (perhaps by adding TextIterator::BYTE constant). -Andrei Edward Z. Yang wrote: Andrei Zmievski wrote: Maybe TextIterator can be backported from HEAD, because it allows for just that. foreach (new TextIterator($str) as $c) { ... } IIRC, TextIterator is specifically designed for Unicode, letting you iterate over codepoints, combining sequences, characters, words, etc. So making it do all that would only make sense with intl, and even then not really (as Stanislav points out performance-wise). What I was suggesting was a shortcut to iterating over binary data; i.e. byte by byte. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] [PATCH] make it possible to skip very slow tests
Steph Fox wrote: Hi again, I'm using this locally because two of our tests take over 10 minutes each to run on my laptop, and I run the relevant bits of test suite every time I make a change. All it does is adds another option, -x, to run-tests.php. This sets an environmental variable which can then be checked for in the SKIPIF section of very slow-running tests. Any objections if I commit it in 5_3/HEAD? I'd prefer a run-tests.php option that sets the timeout limit in seconds. Chris -- Christopher Jones, Oracle Email: [EMAIL PROTECTED]Tel: +1 650 506 8630 Blog: http://blogs.oracle.com/opal/ Free PHP Book: http://tinyurl.com/f8jad -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php