• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

WP Realm

WordPress news, community news, reviews and more from all over the world

  • News
  • Reviews
  • Tutorials
  • eCommerce
  • About
  • Contact

Using PHP Closures in WordPress

14 November 2012 by Joe Hoyle 19 Comments

There has been little discussion on the use of PHP Closures with WordPress code, hopefully we will be able to spark some here! Before getting into the nitty-gritty, to make sure everyone is on the same page a quick explanation of a PHP Closure.

Anonymous functions, also known as closures, allow the creation of functions which have no specified name. They are most useful as the value of callback parameters, but they have many other uses.

php.net

Why Use Closures?

The ability to create single-use callback functions can be very useful when developing in WordPress land, as it’s very often one needs to run code via hooks and filters. At its simplest consider the following code:

function jh_excerpt_length() {
return 50;
}
add_filter( 'excerpt_length', 'jh_excerpt_length' );
view raw simple.php hosted with ❤ by GitHub

A very basic example, but something seen often. Now the example using a PHP Closure:

add_filter( 'excerpt_length', function() {
return 50;
} );
view raw closures-simple.php hosted with ❤ by GitHub

With the Closure you are essentially passing a function object directly to add_filter() that will be called when the hook fires. I prefer this for a couple of reasons.

  1. I don’t need to think of pointless names for functions that are only used for a specific hook (e.g. jh_plugin_init()).
  2. The Closure is only one statement, so all the code is encapsulated into one block. When working on a large project, I don’t want 100 named functions all created at the “top level” of the code hierarchy, when in reality many functions only exist to be called once via other functions and hooks. I want the code to flow in the same way the model in my head appears. To illustrate this:
function jh_plugin_init() {
if ( function_exists( 'w4tc_cdn' ) )
add_action( 'load-post-new.php', '_jh_add_parse_query_action' );
}
add_action( 'init', 'jh_plugin_init' );
function _jh_add_parse_query_action() {
add_action( 'parse_query', '_jh_add_query_var_to_parse_query' );
}
function _jh_add_query_var_to_parse_query( $wp ) {
$wp->query_vars['post_type'] = 'page';
}
view raw controved.php hosted with ❤ by GitHub

The above example is a little contrived, but it demonstrates how all the code becomes 1 dimensional. To me – the following fits better with how I think about code. The fact I need to use functions is a distraction, if I was not confined to hooks/filters I would not split the above into separate functions.

add_action( 'init', function() {
if ( ! function_exists( 'w4tc_cdn' ) )
return;
add_action( 'load-post-new.php', function() {
add_action( 'parse_query', function( $wp ) {
$wp->query_vars['post_type'] = 'page';
} );
} );
} );
view raw closure-contrived.php hosted with ❤ by GitHub

To me this makes more sense when it comes to trying to find out what is happening and where. I am to be able to plug the code in where I want to run it, rather than having to sift though function declaration after declaration to see what’s running where. Named functions should be used for reusable code blocks, often I find most of the modifications made by hooks are not that.

Why not use Closures?

The majority of development work I do is on client projects, and other for-purpose applications rather than distributed plugins or themes. For me this means “get code hooked into WordPress where you need to, and make it do what you want it to do”. Plugin / theme development isn’t necessarily like that, you have considerations of third parties interacting with the code, you have to make sure you are not swallowing a hook's already altered output and provide ways for users to change how things work in a configurable way. This leads to when it’s not so great to use closures.

  • Where anything is likely to want to remove a function you have created (you can’t use remove_filter() with a Closure, as there is no function name), as stated above – not great for distributed code.
  • Closures are PHP 5.3+ only, which means if you want to support all WordPress installs, they are a “no go”. However, anyone running PHP 5.2 should upgrade to 5.3 as it has numerous benefits over 5.2 in terms of performance and language features.
  • Where you are likely to want to use the function multiple times, from different scopes.
  • When you need the function to be accessible at all times (e.g. wp_schedule_event() callback.

As you can see Closures certainly aren’t the answer in many situations, but do have their uses. If they let you be more productive when coding and the environment you are working in allows it then I think we should embrace new language features like this. This is just some examples of how I use Closures with WordPress, I am looking forward to discussing the benefits / disadvantages with everyone below.

 

ShareTweet

Filed Under: Practical Tagged With: php

Reader Interactions

Comments

  1. Tom Willmot says

    14 November 2012 at 17:38

    I used a closure on my site and now it’s a white screen, Thanks very much for your great advice!

    NOT.

    Reply
    • Joe Hoyle says

      14 November 2012 at 17:39

      Sounds like you are running PHP 3.0, I presume your sysops beardy man told you you need to run on Centos 1.1 because that’s secure 😉

      Reply
    • Tom Willmot says

      14 November 2012 at 17:42

      Turns out it was an unrelated issue caused by the fact that I have 5 different related posts plugins active on my site.

      Reply
  2. Edward Caissie says

    14 November 2012 at 17:39

    I just released a minor plugin to the repository that uses these “closures” (BNS Bio) only to quickly find out that I will need to re-write (scheduled for Nov 20) them for optimal compatibility since a recent tweet I read indicated 66% of WordPress installations are running PHP 5.2

    Otherwise, I would definitely be looking to make more uses of this functionality as I agree with most all of your discussion points.

    Reply
    • Joe Hoyle says

      14 November 2012 at 17:41

      Yeah, it’s a shame so many people are still running 5.2 which makes the plugins directory a no go for any recent PHP features.

      Reply
      • Edward Caissie says

        14 November 2012 at 17:59

        I wrote the plugin more as a teaching aide for an upcoming Meetup presentation I am doing, thus the November 20 re-write … the WordPress repository seemed the better place of all the options to distribute from. Fortunately I already covered setting up a local test environment, so everyone should be using PHP 5.3+ in those.

        Reply
  3. Robert O'Rourke says

    14 November 2012 at 17:43

    Great roundup Joe.

    This approach fits my thinking too but the alternative is a habit I’m only just starting to break. I’ve to use this approach the most when I have theme specific settings registered using the settings API that needs more validation logic than a simple sanitise eg:

    add_settings_field( 'id', __( 'Field name' ), ... etc... );
    register_setting( 'general', 'option_id', function( $value ) {
    return array_filter( $value, function( $v ) {
    return is_int( $v );
    } );
    } );

    It feels a lot like javascript/jQuery in some ways which I really like.

    I’m in 2 minds as to whether to use the approach for some client sites even though I have full control – part of our offering is that the code is GPL so they can take the code with them and that can mean it’ll break if they have crap hosting. Not a huge problem in reality though 🙂

    I guess it depends on the job – if it’s likely to become complex through scope changes/feature requests then classes and helper classes are a more flexible and perhaps more maintainable approach to take.

    Reply
    • Joe Hoyle says

      14 November 2012 at 17:56

      Yeah, I use them a lot for PHP only stuff like array_map, usort, array-filter etc, so much better than doing string name callback!

      For client work, we are generally pretty upfront about the fact they will need PHP 5.3. I certainly don’t want to be working on a long term project and be stuck with 5.2, especially when it’s not such a big deal to have them upgrade PHP. I don’t think there are many sounds arguments for running 5.2, maybe some LTS distros don’t have access to it yet.

      Reply
  4. Steven Jones says

    14 November 2012 at 17:44

    Thanks for that Joe – I didn’t know closures were anonymous functions.

    I’ve always found it a bit unorganised having an add_action or add_filter just somewhere in the script. Sometimes the hook is above a function, sometimes below – sometimes nowhere near it.

    I think it adds much needed structure to the code and whereas they can’t always be used they’re definitely a step in the right direction for WP when it supports PHP 5.3.

    Reply
  5. Owain Cuvelier says

    14 November 2012 at 17:57

    Nice one Seph.

    I’ve only ever known closures as anonymous functions, so that helped clear some things up.

    The way I see it, it’s a lot nicer seeing it that way, it seems five times easier to read.

    Reply
  6. Nuno Morgadinho says

    14 November 2012 at 19:30

    Great writeup Joe, thanks!

    I’m generally against using anonymous functions but your post got me thinking again about it. Would you suggest then using closures for client projects and other for-purpose applications and avoiding them in Plugin / theme development?

    Reply
  7. Ryan Meier says

    15 November 2012 at 14:30

    I had no idea you could do this in php. Reminds me of javascript closures now.

    Reply
  8. Tom J Nowell says

    20 November 2012 at 11:21

    With the Closure you are essentially passing a function object directly to add_filter() that will be called when the hook fires. I prefer this for a couple of reasons.

    There’s a problem here. You say effectively, but actually, the word literally would be more appropriate.

    PHP 5.3 doesn’t support true closures, rather it’s a compiler trick. For example take this example:

    $func = function($x){ return $x +1; }

    Here you would expect that the function defined is a first class citizen and that $func is holding an anonymous function. Wrong.

    Here, $func is actually an object of type Closure.

    Both of these do the same thing:

    $func(5);
    $func->__invoke(5);

    To make matters worse, anonymous functions still aren’t quite first class citizens in PHP 5.3, and a subtle distinction is missed

    $anonymous_f = function(){ echo ‘anonymous’; }
    $x = 5;
    $closure = function() use($x) { $x += 5; }

    A closure is an anonymous function that modifies things outside its definition. In PHP to use a true closure you must explicitly specify the variables that are going to be modified. Here $anonymous_f is not a closure, but a mere anonymous function.

    http://php.net/manual/en/class.closure.php

    Anonymous functions, implemented in PHP 5.3, yield objects of this type. This fact used to be considered an implementation detail, but it can now be relied upon. Starting with PHP 5.4, this class has methods that allow further control of the anonymous function after it has been created.

    Besides the methods listed here, this class also has an __invoke method. This is for consistency with other classes that implement calling magic, as this method is not used for calling the function.

    Reply
    • Joe Hoyle says

      20 November 2012 at 11:39

      Hi Tom,

      > There’s a problem here. You say effectively, but actually, the word literally would be more appropriate.

      I didn’t say effectively I said essentially, and as you point out, a function is not a first class object, it’s a Closure, so it’s not “literally” a function.

      I think you are being over pedantic about the implementation of closures, there is little difference from the programmers perspective, regardless of the compiler’s decisions. You can create a “function” object, assign it to a variable and invoke the function as expected. You can also inherit variables from the parent scope – in most cases you don’t need more than that, and in 90% of cases it will work just fine.

      Sure, it’s not as versatile as JavaScript closures with a different scope model, but it’s a sure improvement (or at least another string to the bow) on named functions and classes. I am sure you have been using PHP long enough to realize it doesn’t implement everything the way a lot of people would like.

      Reply
      • Tom J Nowell says

        20 November 2012 at 15:25

        I wouldn’t take it as criticism, I mention it because it points out some further bits that people may not know that leads to plenty of cool stuff like alternative implementations of iterators by swapping out the internal scope of an anonymous function =]

        Reply
  9. Theo says

    21 November 2012 at 15:31

    I copied out your example code in the picture and now my website says ‘syntax error, unexpected ‘}”, is it meant to do that?

    Reply
  10. Dietmar says

    10 December 2012 at 09:40

    I must admit that I never heard of php closures. Allthough hearing about it is really great for it seems to make some of my former dreams come true. It would be a great thing to reduce a lot bunch of functions that only return a single value and so on (as mentioned in the article). As long as you work only for clients and not for theme parks like themeforest etc it is okay.

    Reply
  11. jtsternberg says

    16 April 2015 at 00:41

    Pitching in, closures should be very carefully considered before they are implemented as they effectively disable the remove_action/filter functions. I think closures can be short-sighted and somewhat of a ‘cheat’. But I can also see a few valid cases where they are handy and harmless.

    Reply

Trackbacks

  1. BlogBuzz November 17, 2012 says:
    17 November 2012 at 13:55

    […] Using PHP Closures in WordPress […]

    Reply

Leave a Reply Cancel reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

SUBSCRIBE

Our posts to your inbox. It's a wonderful thing.

Recent Comments

  • Remkus de Vries on Building a Multilingual Website? These are the Questions to Ask.
  • Tuba on Building a Multilingual Website? These are the Questions to Ask.
  • WPML, qTranslate eller Polylang: hvilken du skal velge og hvorfor? (2020) - My Blog on Building a Multilingual Website? These are the Questions to Ask.
  • Marian Malahin on Building a Multilingual Website? These are the Questions to Ask.
  • WPML,qTranslate X或Polylang – 三种最流行的多语言WordPress插件比较(2019) – wordpress on Building a Multilingual Website? These are the Questions to Ask.
Copyright © 2012 – 2023 WP Realm
Have you seen how fast Servebolt serves this site?