#StandWithUkraine

Closures crash course for WordPress developers

WordPress core is about to raise minimum PHP requirement to version 5.6. That brings a wider access to cutting–edge nine years old features, such as anonymous functions (aka closures).

Closures had immediately generates some push back against using them with WordPress hooks. That is where they can shine though!

Inline callbacks

Closure in PHP is a callable. You can use closure like any other callable. Both simpler (functions) and more complex (invokable classes).

In WordPress the common use of callable is a hook callback:

add_filter( 'answer', function () {
	return 42;
} );

So closure can be a quick way to write a callback inline. Closures have many more uses, such as strategies and lazy service definitions.

Scope inheritance

A trivial function callback will only have access to its argument. And a global scope, which is a bad idea.

Closure has another way — it can inherit from parent scope:

foreach ( [ 32, 42, 52 ] as $answer ) {

	add_filter( "answer_{$answer}", function () use ( $answer ) {
		return $answer;
	} );
}

This will create three different callbacks from one definition. Technically anonymous function is a Closure instance. So every time we create a new instance and it can inherit what we want from the current scope.

This is very powerful way to build elaborate callbacks that combine logic with data.

Object binding

Wait, if a closure is an object, does it have $this ? Not a random question. A closure defined inside a class binds to the object’s context so $this refers to the object, not closure itself:

class Answer {

	private $answer = 42;

	public function __construct() {
		add_filter( 'answer', function () {
			return $this->answer;
		} );
	}
}

This is also a very powerful feature. We can build complex callbacks with access to object’s private methods and properties without exposing them as public API.

Removing from hooks

And here is the downside. In WordPress to remove an object–based callback from a hook you need access to the original instance. Without it there is no way to communicate to API which callback you want to be removed.

With closures this can be a challenge. More so when interacting with callbacks from code that is not your own.

But it is shortsighted to consider this downside of a closure! It is much more of a shortcoming on the side of WordPress core.

If you worry about this aspect there are both solid materials on removing closures and a ticket to improve this in WordPress core.

Overall

Anonymous function is a powerful PHP feature. It can be used to build both trivial and elaborate callbacks. Closures have unique abilities to inherit from parent scope and access the object where they were defined.

In WordPress context you don’t want to use closures excessively for hook callbacks, due to current API limitations.

But don’t hesitate to explore them for complex use cases! The benefits of closure outweigh the downsides.

Related Posts

3 Comments

  • Slava Abakumov #

    Using `$this` in a closure technically possible starting from PHP 5.4. IMO that should be noted. If one needs to support PHP 5.3 - the only way around is using `use ( )` syntax to pass the outer values into the closure.
  • Andrey “Rarst” Savchenko #

    WordPress is going to 5.6, so 5.3 vs 5.4 is not relevant for that context.
  • Slava Abakumov #

    I disagree, WP <= 5.1 will be a huge percentage for quite a long time. Ditching it without a 2nd thought is business-wise a very unwise decision.