Me griping about PHP :) (closures this time)

Yeah, that’s about all this post will be. I read an article from IBM developerworks on the upcoming 5.3 features, and something got my dander up: closures.

I first got acquainted with closures in Groovy last year, and love them. They make sense. The syntax is pretty easy, and feels natural in the language. Not so in PHP. Once again, inconsistencies are not just legacy issues in PHP – they are created anew for us to deal with for years to come.

Look at the example here:

class Dog
{
 private $_name;
 protected $_color;

 public function __construct($name, $color)
 {
  $this->_name = $name;
  $this->_color = $color;
 }

 public function greet($greeting)
 {
  return function() use ($greeting) {
   echo "$greeting, I am a {$this->_color} dog named
   {$this->_name}.";
  };
 }
}

Given that ‘anonymous function’ inside the greet() method is a closure, WHY NOT NAME IT THAT? The PHP Reflection API was updated to include a “getClosures()” method, but what would you get? They keyword “closure” doesn’t exist, but could have. Instead we now have the keyword “function” looking like two different entities – it looks like a function call when used with the () directly after it, and also has its traditional function fname() syntax still available.

I have to teach this stuff, and being explicit with a closure keyword would have saved a lot of headaches to come in explaining this stuff to people. Additionally, it would have been less to type.

Compare

return function() use ($greeting) {
 echo "$greeting, I am a {$this->_color} dog named {$this->_name}.";
};

with

return closure($greeting) {
 echo "$greeting, I am a {$this->_color} dog named {$this->_name}.";
};

What’s more explicit, easier to understand, and fewer characters to type? Given the recent namespace separator debacle (using \ as a namespace separator, and justifying it because it’s “fewer characters to type”), I can’t really understand the rationale behind the closure syntax.

To be fair, the closure syntax RFC was up at http://wiki.php.net/rfc/closures and I didn’t comment in time. So, I guess it’s all my fault. :( Beauty and elegance have never been PHP’s strong suit, but it seems people went out of their way to make this unintuitive and bulkier than it needed to be. :/

On a more broad note, I really think the bulk of these changes (closures, namespaces, etc.) should have been put in php6 only, not in the 5.3 series.  I understand the need for testing and such, but we’re implementing new functionality and defining how it is expected to work based on the current PHP5 Zend Engine.  Whatever useful changes that might make a PHP6 faster/better/whatever can’t easily be implemented because the ‘new’ features are all dependent on a core engine that’s already 5 years old, which it itself was built with an eye towards backwards compatibility to PHP3.  Strategically, it just feels like the wrong move.  But hey, what do I know, right?  I can’t write C code patches, so my views don’t really have much weight, do they?


I'm currently working on a book for web freelancers, covering everything you need to know to get started or just get better. Want to stay updated? Sign up for my mailing list to get updates when the book is ready to be released!

Web Developer Freelancing Handbook

Share and Enjoy:
  • del.icio.us
  • DZone
  • Facebook
  • Reddit
  • StumbleUpon
  • Digg
  • Simpy
  • Technorati

Tags:

{ 25 comments to read ... please submit one more! }

  1. Jonathon Hibbard

    Honestly, I don’t understand what the fuss is all about. This same tecnique has been used for years with mutliple other languages and I’d say you won’t even see a big issue with using them the same way in PHP.

    I can, however, see where you would want to have a “closures” method indicating this instead of an anonymous function. It kind of makes sense to just name the method “closure” for descriptive meaning sakes, but at the end of the day, does it really matter?

    (Sorry about above, I just saw you read the wiki article ;)

    Anyways, with regard to namespaces I can agree with you here. I think it’s a very big mistake to include a big change to the the stack by implimenting namespaces in a 5.3 release. The main reason is because now if there are bugs, you take a stable 5.3 release and turn it into a beta pre 6.0 release. But maybe that’s what they’re doing. They’re trying to work the bugs out with the current 5 version to have it perfected in 6.

    I dunno. But I DO know that Zend’s Engine is going to get worse before it gets better. They already are proving that with their new “Zend Eclipse IDE” release which is a TOTAL GARBAGE PIT! But, I’ll end that there before going on ranting.

  2. I’d say it does matter some when people come to learn it. In Reflection class they’re called “closures”, but when you’re writing them, you use an anonymous “function” definition. This is indicative of a continued lack of focus in the development of the PHP language. One can make the argument for inconsistency in the infamous “needle/haystack” examples that because PHP was primarily wrapping pre-existing C libraries, argument order wasn’t as easy to maintain. If 5 db vendors exposed different ways of doing things, PHP’s path of least resistance was to simply wrap the APIs each DB vendor exposed. Not pretty, but somewhat justifiable because there were already existing “standards” to interoperate with.

    Naming closures “closures” in one area of the language, but not in another is highly inconsistent. Again, when you’re try to explain this stuff to people (IE – teach it) it’s just an extra “gotcha” to remember. And there’s *no* *technical* reason for these inconsistencies to still be happening 2008.

    I’ve been thinking since around 2004 that a major company would fork PHP5 and bring stability and process to the language development proceedings, but alas, it hasn’t happened. IBM and Quercus have come somewhat close, in that they have alternate PHP engines, but neither will ever hit mainstream use by the majority of PHP developers. And even in those cases, they’re trying to mimc current PHP functionality as much as possible, rather than chart a new, more stable, course.

  3. I apologize in advance for being riled up, I mean no disrespect.

    [isthisforreal?]
    I know what you mean, all this inconsistency has made it impossible for me to write any useful software in PHP (phpDocumentor, PEAR Installer, these are all examples of the useless crap I’m talking about), and PHP 5 just makes it that much harder to do anything useful.

    For instance:

    methods in classes are declared using “function,” this has caused all kinds of difficulty, when I teach people about it, they take almost 30 seconds to understand the difference, it’s horrible.

    Hell, it took me almost 2 days to figure out why variables were accessed as $varname and declared as “var $varname” in a class, but used as “$this->varname” instead of “$this->$varname” when I was learning PHP 4.
    [/isthisforreal?]

    Actually, PHP is just fine. Personally, I think you’re complaining about ridiculous things. Not only does PHP 5.3 have many useful new features, it is up to 30% faster than any previous PHP version. Where is the real problem?

    Want to know a real headache?

    I started using PHP because I had a database program written in MS Access, in which I was spending fully 85% of my time working around bugs in MS Access. After 2 months of struggling, I ported the whole thing to PHP 4/Mysql with more features in 15 hours, encountering not one bug in either program.

    I am in the process of porting an app I wrote in PHP/mysql/javascript to Objective C/Cocoa because it really is a desktop app, and needs to be easier to install on the host machine, and am spending about 90% of my time working around bugs in Appkit and its poor documentation.

    Stop whining! It is your fault because you can easily make a real difference but instead choose to complain here where it has no helpful effect. Many people who do *not* code in C contributed voluminously to all of the discussions of things you are only blogging about, and yes, it did make a difference in how things were implemented.

    Closures, in fact, had a relatively civil discussion of syntax and the problems, not the least of which is that every new keyword introduced breaks pre-existing code, which is one of the main reasons “import” was swapped for “use” in the namespace implementation. This is why “function” is used instead of “closure”. Of course, you would probably understand this better if you were constructively or even passively involved in the process.

    Let’s all take a reality check: PHP 5.3 is in the alpha stage, and there is much testing to be done prior to beta. This is not being rushed out the door like 5.0.0 was, 5.3 will be as stable or more stable than 5.2. Have an issue? Be a good citizen and contribute where it actually makes a difference: the bug tracker or the mailing list.

  4. While the RFC page is named “closures” the features added are both anonymous functions and closures.

    An anonymous function can be created by just not including the “use” keyword to bind variables from the local scope. In this case the name closure would not make any sense and would be more confusing.

    In addition, your example of simplifying a closure with no parameters and a single bound variable to closure($var) looks nice and all, how are you going to handle a closure that actually accepts parameters? This is why the extra “use” syntax in function ($param) use ($local_var) { ... } exists.

    In a language like javascript, that many developer are familiar with and that include closures, there is no indication that a closure is happening. I would think the “use” keyword in PHP would make it that much more obvious to those learning about closures.

  5. @wbond – my example *does* include a parameter. I guess I’m just not at all getting what ‘use’ brings. Importing variables from the outer local scope? If so, why that? Why not just allow anything inside the outer local scope to be referenced? Inserting the word “closure” in there would indicate that a closure is being used, more explicitly than seeing that “use” is used.

  6. @Greg Beaver:
    Let’s all take a reality check: PHP 5.3 is in the alpha stage, and there is much testing to be done prior to beta. This is not being rushed out the door like 5.0.0 was, 5.3 will be as stable or more stable than 5.2. Have an issue? Be a good citizen and contribute where it actually makes a difference: the bug tracker or the mailing list.

    Welcome to the world of PHP, you must be new here.

    PHP developers *DO*NOT* read bug reports. Most get marked as “bogus” without even being properly read. And the “requests for comments” go on without any acknowledgement of comments being recieved.

    Complaining loudly on a blog is the only way that you can contribute to PHP unless you’ve been invited into their secret little world of developers with a tenuous grasp on OOP. I remember asking for static class variables in ’02 and getting laughed, saying that all you have to do is

    $a = new A();
    $b = new A();
    $a->count++;

    Voila….. static class variable equivalent.

    Not much has changed, all my patches and bug fixes get sent out the door as bogus, like my short-tags/XML fix, the fix that actually makes exceptions behave like exceptions, instead of like warnings…. mmm.. I can’t think of the rest right now. But I’m sure you have 1 example of some idea about the comments in the php.ini that you contributed and now you think PHP is teh best community in teh world!

  7. @Greg Beaver

    How about you stop complaing that too many people are complaining and actually *do* something about the problem. Unless of course you just don’t agree with the solution, in which case telling someone to “submit a bug report” is a tad bit “ad hominem”.

  8. I have yet to find a language that uses the keyword “closure”. Javascript uses the keyword “function” when defining closures. Perl, Python, and Ruby use anonymous blocks (though both ruby and python optionally allow the “lambda” keyword). Personally, to me, it feels like the PHP devs are semantically tying closures to anonymous functions — and I’m fine with that. It feels like a natural association, and makes it easier to teach closures to those who know what functions are.

  9. @mark

    That last dig @greg was out of line. Greg has contibuted a lot to the PHP community over the years.

    I know you’ve submitted patches, and I think they tend to get rejected because you’re basically not an ‘insider’. I’m not sure how many functionality patches are taken from people who aren’t long-term people on the PHP mailing list. There may be good reasons for that, but at the same time, I submit that PHP is missing out because of that.

    Where is a PHP ‘suggestion box’ site? I don’t see an effective way of ‘outsiders’ submitting ideas/patches/suggestions in an open and trackable way. Mailing lists are noisy, and are hard to search through long term in a standard way. The ‘bug reporting site’ – not appropriate in most cases. The ‘rfc’ page – you can’t just post. You have to register and be approved (not a HUGE impediment, but may take time and may lose people with a good idea).

  10. Specifically, where is the PHP equivalent to Python’s http://www.python.org/dev/peps/ ?

  11. PHP developers *DO*NOT* read bug reports. Most get marked as “bogus” without even being properly read.”

    http://bugs.php.net/search.php?cmd=display&search_for=kimsal&x=0&y=0

    that’s all about you reporting bugs? One has been fixed, the other is your fault and is actually not a bug (and Christian has read the report).

    There is a difference between writing (yet another) rant about something you dislike in PHP. However your rants are somehow irrelevant as you never joined any discussions on internals. Ah right, we will not read your posts anyway :D

  12. Hi Michael,

    I think the reasons is that all anonymous methods aren’t closures. I’d complain more about the reflection API, since not all anonymous methods are closures. Closure is typically a side effect of anonymous methods or lambdas.

    e.g.
    return function() use() { return 1; };

    doesn’t encapsulate any variable from the parent scope, thus there is no closure.

    If this anonymous metehod shows up via reflection, when asking for “closures” then its simply a poorly named API.

  13. @matthew – I have yet to find a language that uses \ as a namespace separator, but that didn’t stop PHP from adopting it anyway. :)

  14. @Michael Kimsal: I agree with you on the name space separator woes but there was a lot of heat and debate over that. The issue came down to resolving function in a namespace compared to a method in a class, e.g. Foo::Bar() (referring to function foo in namespace bar) is identical to Foo::Bar() (static method bar on class Foo). I would have preferred the core team take the C++ route and throw an error if an ambiguous name was declared but *Shrug*.

    As to your question on what use the “use” keyword brings on closures, it appears you’ve already read my blog post where I touched on the existence of closures.

    PHP uses the global keyword to import variables from outside the current scope and rather than forking the global keyword behavior (global returns a reference if you will) and breaking the concept of a closure, they introduced the use keyword to ensure that closures work exactly like regular PHP functions but still provides the ability to import but lock an external variable.

  15. By the way to all the other commentators referencing python:

    Python doesn’t really have closures. At least not the anonymous function style that everyone is referencing. The closest python has to that is a lambda function which cannot even be compared.

    Though there are ways in python to get closure like effects, namely because the scoping is well done and enforced in python.

  16. I’m surprised that nobody’s picked up on a glaring flaw in your proposal – “funciton($arg1, $arg2…) use $bound” allows you to create closures that have both arguments and bound variables. Your suggestion only makes room for the bound variables, significantly reducing the usefulness of the construct.

  17. @sean – i wouldn’t say it’s a flaw. Why not auto-bind whatever variables that are used in the function definition?

  18. Why don’t you just quit bitching, live with it and write awesome code.

    You’ve done the hard bit, you understand the construct. Bitching won’t change the code.

  19. @mgkimsal
    because there are incredibly legitimate reasons why you would not want all of the parameters bound.

  20. Bind the ones that are used in the anonymous function (thereby making it a closure).

    What I’ve just read here is that ‘use’ was used instead of ‘import’, but the idea is to bring in certain variables from the local scope (scope of the code that’s defining the function) to be available in the anonymous function / closure. This feels redundant, and given my experience with closures in other languages, this explicit naming of local variables to be used in the function is not needed.

    Here is where Wez mentions it in passing – “Since everyone has grown up explicitly managing this via the global keyword, I think it makes a lot of sense to use similar syntax for getting at those lexical values.” So, this seems it’s more of a style issue than a technical one. It would seem that any reference to a variable that’s not defined in the anonymous function could check the variable names of the parent code where it was defined to see if it exists there, then import it. But that’s not how it’s done – we use the ‘use’ keyword, which I’m simply saying isn’t something I care for.

  21. Perhaps it would be wise to teach something other than PHP. Learning PHP has no value other than if you are going to write PHP, because of all the inconsistency and ugliness, whereas many other languages have useful things to teach you about programming.

  22. People are paying to learn how to write PHP, and it has some value to them in that regard.

  23. Thread has died down but I’ll ask (maybe someone will pick this up and clarify).

    How many (and/or which) changes to PHP of any moderate complexity or significance have been introduced by people who did not also simultaneously (or near enough) submit a proof of concept of their enhancement with a code patch? A quick look at wiki.php.net/rfc shows that about half of the RFCs have patches with them, and many of the ones that don’t aren’t really code related (“siberia”, etc.) Also, why is it called an RFC system if there’s no place for people to leave comments on the page?

    My initial stab (not done) at an RFC is http://wiki.php.net/rfc/automatic_get_set_methods – it really is a “request for comments” but since there’s no place to put comments there, feel free to comment here or on my earlier post about get/set stuff.

  24. I think its worth noting that at least as of PHP 5.3.0-RC5-dev, the ReflectionMethod::getClosure() method was removed due to issues with how the PHP engine should resolve the <strong$this keyword. I’ve been struggling to find another way to get a closures for methods (including protected and private) within the context of an object since discovering the functionality I thought existed was yanked.

    I have come across this blog-posting several times while doing these searches and thought this might be useful details for whoever is struggling with closures as well.

    I filed a bug report on the PHP bug tracker, which has since been closed as bogus, where the removal of getClosure() was cited.

    Bug #48654 ReflectionMethod::getClosure() Undefined on Windows binary for PHP 5.3.0RC5-dev

{ 1 Pingbacks/Trackbacks }

  1. Michael Kimsal’s Blog: Me griping about PHP :) (closures this time) : WebNetiques

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">



0.27058911323547