PHP’s Magic __invoke() Method and the Callable Typehint
__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:
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 …;
}
}
Very interesting – didn’ t know about this new method.
This page served as a good intro to magic methods in general – thought i would share:
http://www.programmerinterview.com/index.php/php-questions/php-what-are-magic-functions/
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.
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.
even pimple relies on this
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]
use:
<?php
if (is_callable($bob)) {
echo 'Call bob'
}
Pingback: DunglasActionBundle: Symfony controllers, redesigned - expert Symfony et e-commerce - Lille
Pingback: DI Factories for Slim controllers | Rob Allen's DevNotes
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.