PHP’s Magic __invoke() Method and the Callable Typehint

PHP has a variety of magic methods; methods named with two underscores at the start, which get called automatically when a particular event happens. In PHP 5.3, a new magic method was added: __invoke().

__invoke()

The __invoke() method gets called when the object is called as a function. When you declare it, you say which arguments it should expect. Here’s a trivially simple example:


class Butterfly {
  public function __invoke() {
    echo "flutter";
  }
}

We can instantiate a Butterfly object, and then just use it like a function:


$bob = new Butterfly();
$bob(); // flutter

If you try to do the same thing on an object without an __invoke() method, you’ll see this error:

PHP Fatal error:  Function name must be a string in filename.php on line X

We can check if the object knows how to be called by using the is_callable() function.

Callable Typehint

In PHP 5.4 (the newest version, and it has lots of shiny features), we have the Callable typehint. This allows us to check whether a thing is callable, either because it’s a closure, an invokable object, or some other valid callback. Another trivial example to continue the butterflies and kittens theme:


function sparkles(Callable $func) {
  $func();
  return "fairy dust";
}

class Butterfly {
  public function __invoke() {
    echo "flutter";
  }
}

$bob = new Butterfly();
echo sparkles($bob); // flutterfairy dust

So there it is, one invokable object being passed into a function and successfully passing a Callable typehint. I realise I also promised kittens, so here’s a cute silver tabby I met the other day:

merlin

11 thoughts on “PHP’s Magic __invoke() Method and the Callable Typehint

  1. Btw, pretty much nobody uses __invoke in PHP, but it is something very common in other languages. E.g. in C++ you commonly define Functor classes:

    class Hasher {
    unsigned long operator()(const Obj& obj1, const Obj& obj2) {
    return …;
    }
    }

  2. Thank you Lorna, I needed to know exactly why and how the __invoke() method in ZF 2 helpers works. This post was the third in search results and the first with a good title.

    @Nikita Everybody using ZF 2 with view helpers uses __invoke a lot.

  3. just want to say that what is true one day is a not next day, or it was never true :)
    a lot of invoke usage in architectures EBI with interactors on silex, symfony2 and libraries.

  4. The Callable type hint is awesome but what if I want to check in an if/else situation?
    instanceof Callable does not appear to work.
    <?php

    $bob = "blah";

    if($bob instanceof Callable) {
    echo "x";
    }

    • Jesse, you want to use the is_callable($bob) . Callable is *only* available as a type hint.
      http://www.php.net/manual/en/language.types.callable.php

      [code]
      function sparkles(Callable $func) {
      $func();
      return “fairy dust”;
      }

      class Butterfly {
      public function __invoke() {
      echo “flutter”;
      }
      }

      $bob = new Butterfly();
      echo sparkles($bob), “\n”; // flutterfairy dust

      if( is_callable( $bob ) ) {
      echo ‘Can call $bob’, “\n”;
      }
      [/code]

  5. Pingback: DunglasActionBundle: Symfony controllers, redesigned - expert Symfony et e-commerce - Lille

  6. Pingback: DI Factories for Slim controllers | Rob Allen's DevNotes

  7. In my case, __invoke has come in handy when I wanted to transform the class autoloading process into an OOP one:
    – I created a class that acts as an autoloader for a specific location where classes are stored.
    – I can then pass this class to spl_autoload_register which takes a callable as first argument and will indeed be able to load a class upon request using the Autoload object provided.
    Just to give you an idea of what I mean:
    define(‘AUTOLOAD_PATH’, dirname(__FILE__).DIRECTORY_SEPARATOR);
    define(‘AUTOLOAD_EXTENSION_SUFFIX’, ‘.php’);

    class Autoload {
    public static Autoload function register(string $base_path = null, string $path_suffix = null, bool $throw = true, bool $prepend = false);
    public static bool function testPath(string $path);
    public string function unify(string $class_name, string $base_path = null, string $path_suffix = null);
    public mixed function __invoke(string $class_name);
    }
    To get back on __invoke, in this case Autoload::register will create a new Autoload object and pass it to spl_autoload_register and return Autoload object.

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

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

To respond on your own website, enter the URL of your response which should contain a link to this post's permalink URL. Your response will then appear (possibly after moderation) on this page. Want to update or remove your response? Update or delete your post and re-enter your post's URL again. (Find out more about Webmentions.)