It is possible to treat a class instance as a function in PHP. Quite often this is referred to as a functor even though it should really be known as a function object. This is because functions actually serve a different role in languages that support their use.
The convenience of having a reusable function that can be overloaded and carry a context is something to weigh up against using functions or closures.
<?php
class MyFunctionObject {
public function __invoke($name) {
echo "My name is $name.";
}
}
$MyFunctionObject = new MyFunctionObject;
echo $MyFunctionObject(‘Simon’); // My name is Simon.
The usual method for creating autoloaded functions is to create them as static methods on a class. This does work, but of course carries with it no context.
<?php
class MyStatic {
public static function myName($name) {
echo "My name is $name.";
}
}
echo MyStatic::myName('Simon'); // My name is Simon.
Coming at it from another angle you can also bind closures to class instances. This then allows you access to the classes context from within your closure. Of course you miss out on the autoloading in this case. Also it may make the code harder to read if the binding is not obvious.
<?php
class MyContextClass {
public $context = 'My name is ';
}
$my_function = new function($name) {
echo $this->content . "$name";
}
$MyContextClass = new MyContextClass;
$my_function->bindTo($MyContextClass);
$my_function('Simon'); // My name is Simon
So as you can see a function object is a happy medium that allows you the best of both. The main thing to note is that you can only have one function per object.
An instance of a function can be passed into anything expecting a callable
and it will be executed just like any other function. They also allow you to alias any function object using PHPs namespace syntax:
<?php
use MyFunctionObject as F;
This is a small benefit that you cannot currently get from any other method already discussed. PHP has a pending patch to make this possible with regular functions as well.
There are at least two downfalls of function objects however and the first of which is most annoying. You cannot currently call the function inline without creating the instance.
<?php
$f = new F;
echo $f();
There is currently an RFC and patch targeted at PHP 5.6 that will allow for the following syntax:
<?php
echo new F();
Additionally function objects can be frowned upon as they are not self documenting. Every __invoke()
API can be different making predictable use difficult.
In my research most IDE’s are not able to give parameter hints for the function objects either. Additionally once an object is instantiated it is not clear if it is a function object or not. Without documentation it can be difficult for an implementer to know whether to call it via the function notation or to continue using an OOP So there are a number of reasons that this feature is so underused, but it certainly does have it’s uses. Now you know about it and and how it works you may have the killer blow for that problem that has been nagging you.
note
If you’re interested in more functional techniques like this then checkout my book; Functional Programming in PHP. A guide to advanced and powerful functional programming techniques in your favourite language.