For the most part, all objects implement the Callable Object Pattern. The constructor for each class takes a function, and this function will be called when the object is invoked. Here's an example:

// call some code, capturing PHP triggered errors locally
use \Haldayne\Fox\CaptureErrors;
$capture = new CaptureErrors(function ($input) { trigger_error('Oi!'); return $input; });
$capture->setCapturedErrorTypes(E_ALL|~E_STRICT);
$result = $capture(false);
if (! $result) {
    die($capture->getCapturedErrors()->pop()->get('message'));
}

The generic algorithm here is "capture PHP errors". All CaptureErrors does is wrap the function in a temporary error handler via set_error_handler. You could do this yourself, manually. But there are advantages to building generic algorithms.

And that advantage is?

Composability. Here is a larger example:

use Haldayne\Fox\Retry, Haldayne\Fox\CapturingErrors;

$retry = new Retry(
    $capture = new CapturingErrors(
        function ($src, $dst) {
            return copy($src, $dst);
        }
    )
);

$capture->setCapturedErrorTypes(E_ALL|~E_STRICT);
$retry->setAttempts(5);

$result = $retry('ssh.sftp2://user@host/file', 'file');
if (false === $result) {
    die($capture->getCapturedErrors()->implode(PHP_EOL);
}

Notice how Retry consumes CapturingErrors. These are two independent function objects, oblivious to how each other operates. But they're composed together to solve a problem: retry copying a file while recording the emitted PHP errors for diagnostic purposes.

Take a moment and think about how you would do this with pure functions. In a reusable way. So that you could swap the order in which they're called.

To capture errors, you have to modify and restore global state. To retry, you have to run a loop. You're going to need at least two functions to make these reusable, then you're going to have to wire them up. It's going to be complicated, perhaps impossible.

But with higher-order functions (functions that accept functions), it's astonishlingly easy.

The PHP magic method __invoke() is the syntactic sugar that makes it possible for these two functions to be completely indepedent. They know nothing of one another, but rely on the defined interface: each is callable.