2
\$\begingroup\$

I currently had a colleague reviewing my code and he had a comment on a factory class I created. It's very simple:

class ResponseFactory
{
    public function create(array $curlInfo, array $rawResponse): ResponseInterface
    {
        return new Response($curlInfo, $rawResponse);
    }
}

$responseFactory = new ResponseFactory();
$response = $responseFactory->create(...);

His comment was that I should use the __invoke()-method of PHP. In that case, the code would look like this:

class ResponseFactory
{
    public function __invoke(array $curlInfo, array $rawResponse): ResponseInterface
    {
        return new Response($curlInfo, $rawResponse);
    }
}

$responseFactory = new ResponseFactory();
$response = $responseFactory(...);

Now I am wondering: is this just a matter of taste? Or is there real benefit in using __invoke() over a public create()-method?

Any thoughts or insights on this matter are more than welcome. I'm really trying to find good use cases for the __invoke()-method, but I'm not sure if a factory is one of them.

\$\endgroup\$
1
  • \$\begingroup\$ I'd consider not using factory at all in this case, because it doesn't solve any problem. Hard to see any abstraction in it either, because Response and factory parameters look too specific. If at least one of them would be factory's property then it would make more sense. Now it looks like either class that is calling the factory or some part of it should be factory itself. \$\endgroup\$ – shudder Sep 11 '18 at 19:20
3
\$\begingroup\$

The only benefit of using __invoke() is that you can store the instance of the class in a variable as a callback and then use it without call_user_func_array(). But in my opinion using create() is more readable so you can guess easily what is the code doing.

\$\endgroup\$
1
\$\begingroup\$

I choose __invoke() here for two reasons:

  1. The existence of __invoke() denotes the "primary purpose" of the object. It is designed to do a single thing only, so __invoke() stands out from other public methods when reading the method list of the class as its primary purpose.

  2. The use of __invoke() allows the object to be directly used as callable, without using the more cumbersome [$object, 'create'] notation. This is analogous to the concept of "functors" in C++. Specifically, if a callable is to be passed, but you also want to pre-fill some "state" with it, you can either generate a closure or use a class with __invoke() method. However, in PHP, a class can offer the additional benefit of interfaces so you can implement type-safe callable which isn't possible with traditional closures. This can be used to migrate legacy code to type-safe PHP 7 code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.