UltraMega Blog
27Jul/100

Create Callbacks Using __invoke

The __invoke magic method (available as of PHP 5.3) is used to make an object callable as if it were a regular function. The combines the usefulness of objects with the simplicity of functions. One application of this feature is creating callback functions that can be passed around like objects. This is common practice in other languages like JavaScript, and can be very useful. This tutorial will show you how to create a callback function using the __invoke method.

The Interface

The first thing we should do is create our common interface. This ensures that the callback is usable by enforcing the existence of the required __invoke method. In this example, we'll be using an abstract class as our interface. This gives us flexibility over an interface by allowing us to include shared functionality at this level.

This creates a Callback class type that simply declares an __invoke method with no arguments. Any concrete classes extending this must have the same method. Note the use of the abstract on both the class and method declarations. All abstract methods must be implemented by any class extending the abstract class (unless the extending class is also abstract).

abstract class Callback {
    abstract public function __invoke();
}

The Callback

With our interface defined, it's time to create the concrete Callback class. Here, we'll create a class called MyCallback that extends the Callback class. The body of the __invoke method simply returns the string 'test.' So calling any MyCallback objects as a function will simply return this string.

class MyCallback extends Callback {
    public function __invoke() {
        return 'test';
    }
}

Using the Callback

Now that we have our callback function created, we can actually test it. Here, we create a function that accepts an object of the type Callback (any class extending Callback) and runs it as a function, printing the result. The type hint on the argument ensures that the object uses the Callback interface and is in fact callable, without the need to check it manually.

function testCallback(Callback $cb) {
                    // ^ This is a type hint
    echo $cb();
}

Here is where we create a callback object and then pass it to our test function. The result is the string 'test' being printed, which proves that our callback works!

testCallback(new MyCallback());
// Result: test

Conclusion

Now this was a very roundabout method of printing four characters, but it serves as a demonstration of how you can use the __invoke method to create callbacks. The beauty of this is that calling code never needs to know the name of a function to use it, it just has a reference to it in the form of an object. In real life scenarios, you'd probably create more complex interfaces for different callback types, each with different arguments.

For example, maybe a callback for processing text:

abstract class TextCallback {
    abstract public function __invoke($str);
}
 
class MyCallback extends TextCallback {
    public function __invoke($str) {
        return strtoupper($str);
    }
}
 
function testCallback($str, TextCallback $cb) {
    echo $cb($str);
}
 
$callback = new MyCallback();
testCallback('test', $callback);
// Result: TEST

There are other ways to accomplish callbacks in PHP, such as simply passing the name of a function as a string. However, I like this method because it gives you access to the powerful OOP features. These include, among other things, the interfaces and type hints that ensure the callback is usable without manual checking.

An alternative method of creating callbacks is the use of closures, which were also introduced in PHP 5.3. These actually currently use a built-in Closure class that implements the __invoke method, so it's actually very similar to what we did here.

Posted by Steve

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

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

No trackbacks yet.