Playing with PHP Closures

In my previous post about anonymous functions I mentioned that PHP 5.3 brought in some sweet semantic improvements. Namely, the release introduced the __invoke method and Closure class. Everytime you create a new anonymous function you are actually creating an instance of Closure, and when you execute it function-style you magically called a method. Let's go over this magic method first.

The __invoke method will get called with any passed params when you call it as if it was an anonymous function. No matter what the class is. This can be very helpful if you're building utility-like classes, like I did when I built my timezone converter. Here's an example using slugs from the anonymous functions post.

  1. class urlFriendlySlug

  2. {

  3. protected $trim_slugs;

  4. public function __construct($trim_slugs = true)

  5. {

  6. $this->trim_slugs = $trim_slugs;

  7. }

  8. public function __invoke($string)

  9. {

  10. $string = strtolower($string);

  11. if ($this->trim_slugs) {

  12. $string = trim($string);

  13. }

  14. $string = str_replace(' ', '-', $string);

  15. return $string;

  16. }

  17. }

  18. // example usage

  19. $urlFriendlySlug = new urlFriendlySlug();

  20. $slug = $urlFriendlySlug('Cold Morning Hikes in the Keweenaw');

At first glance this looks a lot heavier than the lambda and closure options. The beauty, though, is that any PHP class can have an __invoke method. You could build a database logging class, one with database connection and preferences injected in the construct, and then call the instance as a function instead of a generic log() method. If you ever build a class with a single public worker method, there's a chance that you can simplify things by making it an invokable class.

So this powerful tool turns classes into callables. So why did PHP go and make a defined Closure class? At first this was a mere implementation detail, though in PHP 5.4 a few more methods got added to a Closure. It was now possible to bind objects to clones of anonymous functions. Which is something that most developers will probably never have to use.

  1. class Post

  2. {

  3. protected $title;

  4. public function __construct($title)

  5. {

  6. $this->title = $title;

  7. }

  8. }

  9. $post_one = new Post('Long Hikes at Huron and Silver River');

  10. $post_two = new Post('Cedar-Cliff Loop of the Huron Mountains');

  11. $urlFriendlySlug = function () {

  12. $string = strtolower($this->title);

  13. $string = str_replace(' ', '-', $string);

  14. return $string;

  15. };

  16. $slug_one = $urlFriendlySlug->bindTo($post_one, 'Post');

  17. $slug_one();

  18. $slug_two = $urlFriendlySlug->bindTo($post_two, 'Post');

  19. $slug_two();

The anonymous function, or the Closure, for urlFriendlySlug will receive a new bound object and will use the second parameter, 'Post', to figure out the class type to determine scope. Since the class type is the same as the bound object, it has scope over the protected property and can do actions based on it. It's a nice way of passing around objects into anonymous functions, and I'd love to find a practical use case to confuse my coworkers with some day.

Out of the two things that modern anonymous functions added to PHP the most useful by far is the __invoke method. Treating functions like objects and objects like functions is a great way to really stretch paradigms. And it can make utility classes very easy to remember and call.