I’ve been working extensively with closures in Ruby for the last few months – they are a necessity if you want to keep your code DRY. We were just getting into closures in PHP using the Kohana framework when we began the move to Rails 3, so we got to see first-hand some of the important differences between the two.
The most glaring difference is in the implementation. In PHP, closures are not first-class functions. They are an instance of the class Closure, with a dynamically defined method __invoke(*args). In Ruby, closures are blocks which are converted into instances of class Proc. Procs are first-class functions in Ruby, so there is no overhead in maintaining closures vs. maintaining strictly defined functions. Also, Proc has a lot of useful methods to it, whereas Closure is basically hidden as an implementation detail.
A result of the difference in implementation is that closed variables have to be defined explicitly in PHP via the use() syntax. This is pretty ugly compared to Ruby, wherein closed variables are handled transparently. Syntactically, the PHP version is uglier; writing your variable names in more places means more lines you have to change if that variable ever contains something unexpected. Also, generally closures are short functions; many closures in ruby can be defined in one line using the {|args| … } syntax. Having to explicitly list all the closed variables can extend even a short block’s definition beyond a one-liner.
There is at least one similarity in that both languages have “early-binding” closures. That is, variables are bound at the time the closure is created, rather than when it is called. This makes closures ideal for callbacks such as iterators and templates, since code can be generated with fixed variables bound to the closure, and more dynamic variables passed as arguments.
All in all, I like working with closures in Ruby much more than in PHP; they feel much cleaner and less hacky. But it’s nice to see the PHP team recognize the usefulness of closures in other languages and frameworks. Hopefully as PHP continues to iterate, we’ll see better versions of closures emerge.