Skip to content

Instantly share code, notes, and snippets.

@settermjd
Forked from Ocramius/README.md
Last active August 29, 2015 14:21
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save settermjd/6222d026da321eba2d4b to your computer and use it in GitHub Desktop.
<?php
final class Login
{
private $sessions;
public function __construct(SessionRepository $sessions)
{
$this->sessions = $sessions;
}
public function __invoke(User $user)
{
$session = new Session($user);
$this->sessions->add($session);
return $session;
}
}
// usage (PHP 7) - see http://3v4l.org/kPnLM:
$session = (new Login($sessionRepository))($user);

__invoke VS function VS Closure

This gist is about:

Mainly:

  • function cannot (should not) be used when side-effects occur
  • function does not work with dependency injection
  • function is not testable in isolation if it isn't a pure function without dependencies

In order to fix the problems exposed above, and avoid global or static scope pollution, two approaches are possible:

Few notes:

  • a class that only implements __invoke and __construct is basically a function combined with a functor
  • a class can be easily tested in isolation
  • a Closure with dependencies cannot be tested in isolation
  • in order to make a Closure testable in isolation, it must be combined with a higher order function
  • there is no runtime difference between using a Closure and any object with an __invoke method defined in its class
  • in PHP, $a = function () use (...) {} simply means "call the constructor of class Closure with these parameters and this body for __invoke", so you end up with an object that implements __invoke anyway.

Therefore, object + __invoke is much simpler and flexible than using a Closure, whereas a function is not applicable in any context that requires the usage of DI.

<?php
// higher order function / factory - you name it
$loginFactory = function (SessionRepository $sessions) {
return function (User $user) use ($sessions) {
// argh! (note that a static registry/locator isn't any better)
global $sessions;
$session = new Session($user);
$sessions->add($session);
return $session;
};
};
// usage (PHP 7) - see http://3v4l.org/kPnLM:
$session = $loginFactory(sessionRepository)($user);
<?php
function login(User $user)
{
// argh! (note that a static registry/locator isn't any better)
global $sessions;
$session = new Session($user);
$sessions->add($session);
return $session;
}
// usage:
$session = login($user);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment