Skip to content

Instantly share code, notes, and snippets.

@GDXbsv
Forked from Ocramius/README.md
Created July 3, 2018 21:10
Show Gist options
  • Select an option

  • Save GDXbsv/d1a729e6a291ba4eb22c643da832b8fc to your computer and use it in GitHub Desktop.

Select an option

Save GDXbsv/d1a729e6a291ba4eb22c643da832b8fc to your computer and use it in GitHub Desktop.

Revisions

  1. @Ocramius Ocramius revised this gist May 20, 2015. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@ Mainly:
    - `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
    In order to _fix_ the problems exposed above, and avoid global or static
    scope pollution, two approaches are possible:

    - using a [`Closure`](http://php.net/manual/en/functions.anonymous.php), combined
    @@ -24,9 +24,10 @@ 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 insulation
    - a `Closure` with dependencies cannot be tested in insulation
    - in order to make a `Closure` testable in insulation, it must be combined

    - 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
  2. @Ocramius Ocramius revised this gist May 20, 2015. 3 changed files with 4 additions and 6 deletions.
    6 changes: 2 additions & 4 deletions __invoke.php
    Original file line number Diff line number Diff line change
    @@ -19,8 +19,6 @@ public function __invoke(User $user)
    }
    }

    // usage:
    // usage (PHP 7) - see http://3v4l.org/kPnLM:

    $login = new Login($sessionRepository);

    $login($user);
    $session = (new Login($sessionRepository))($user);
    2 changes: 1 addition & 1 deletion closure.php
    Original file line number Diff line number Diff line change
    @@ -17,4 +17,4 @@

    // usage (PHP 7) - see http://3v4l.org/kPnLM:

    $loginFactory(sessionRepository)($user);
    $session = $loginFactory(sessionRepository)($user);
    2 changes: 1 addition & 1 deletion function.php
    Original file line number Diff line number Diff line change
    @@ -14,4 +14,4 @@ function login(User $user)

    // usage:

    login($user);
    $session = login($user);
  3. @Ocramius Ocramius revised this gist May 20, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -9,7 +9,7 @@ Mainly:

    - `function` cannot (should not) be used when side-effects occur
    - `function` does not work with dependency injection
    - `function` is not testable in insulation if it isn't a pure function
    - `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
  4. @Ocramius Ocramius revised this gist May 20, 2015. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -30,6 +30,9 @@ Few notes:
    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
  5. @Ocramius Ocramius revised this gist May 20, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@ Mainly:
    - `function` is not testable in insulation if it isn't a pure function
    without dependencies

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

    - using a [`Closure`](http://php.net/manual/en/functions.anonymous.php), combined
  6. @Ocramius Ocramius revised this gist May 20, 2015. 1 changed file with 36 additions and 0 deletions.
    36 changes: 36 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    # `__invoke` VS `function` VS `Closure`

    This gist is about:

    - https://twitter.com/taylorotwell/status/600680897550098432
    - https://twitter.com/Ocramius/status/600705252539691008

    Mainly:

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

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

    - using a [`Closure`](http://php.net/manual/en/functions.anonymous.php), combined
    with a [higher order function](http://en.wikipedia.org/wiki/Higher-order_function) (also called **functor**)
    - using an `object` that implements the [`__invoke`](http://php.net/manual/en/language.oop5.magic.php#object.invoke)
    magic method

    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 insulation
    - a `Closure` with dependencies cannot be tested in insulation
    - in order to make a `Closure` testable in insulation, 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

    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](http://en.wikipedia.org/wiki/Dependency_injection).
  7. @Ocramius Ocramius revised this gist May 20, 2015. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions closure.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    <?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:

    $loginFactory(sessionRepository)($user);
  8. @Ocramius Ocramius revised this gist May 20, 2015. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions function.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    <?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:

    login($user);
  9. @Ocramius Ocramius created this gist May 20, 2015.
    26 changes: 26 additions & 0 deletions __invoke.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    <?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:

    $login = new Login($sessionRepository);

    $login($user);