2017 © Pedro Peláez
 

library invoker

Generic and extensible callable invoker

image

mnapoli/invoker

Generic and extensible callable invoker

  • Friday, April 24, 2015
  • by mnapoli
  • Repository
  • 0 Watchers
  • 0 Stars
  • 1,103 Installations
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 5 Versions
  • 0 % Grown

The README.md

Invoker

Generic and extensible callable invoker., (*1)

CI Latest Version Total Downloads, (*2)

Why?

Who doesn't need an over-engineered call_user_func()?, (*3)

Named parameters

Does this Silex example look familiar:, (*4)

$app->get('/project/{project}/issue/{issue}', function ($project, $issue) {
    // ...
});

Or this command defined with Silly:, (*5)

$app->command('greet [name] [--yell]', function ($name, $yell) {
    // ...
});

Same pattern in Slim:, (*6)

$app->get('/hello/:name', function ($name) {
    // ...
});

You get the point. These frameworks invoke the controller/command/handler using something akin to named parameters: whatever the order of the parameters, they are matched by their name., (*7)

This library allows to invoke callables with named parameters in a generic and extensible way., (*8)

Dependency injection

Anyone familiar with AngularJS is familiar with how dependency injection is performed:, (*9)

angular.controller('MyController', ['dep1', 'dep2', function(dep1, dep2) {
    // ...
}]);

In PHP we find this pattern again in some frameworks and DI containers with partial to full support. For example in Silex you can type-hint the application to get it injected, but it only works with Silex\Application:, (*10)

$app->get('/hello/{name}', function (Silex\Application $app, $name) {
    // ...
});

In Silly, it only works with OutputInterface to inject the application output:, (*11)

$app->command('greet [name]', function ($name, OutputInterface $output) {
    // ...
});

PHP-DI provides a way to invoke a callable and resolve all dependencies from the container using type-hints:, (*12)

$container->call(function (Logger $logger, EntityManager $em) {
    // ...
});

This library provides clear extension points to let frameworks implement any kind of dependency injection support they want., (*13)

TL/DR

In short, this library is meant to be a base building block for calling a function with named parameters and/or dependency injection., (*14)

Installation

$ composer require PHP-DI/invoker

Usage

Default behavior

By default the Invoker can call using named parameters:, (*15)

$invoker = new Invoker\Invoker;

$invoker->call(function () {
    echo 'Hello world!';
});

// Simple parameter array
$invoker->call(function ($name) {
    echo 'Hello ' . $name;
}, ['John']);

// Named parameters
$invoker->call(function ($name) {
    echo 'Hello ' . $name;
}, [
    'name' => 'John'
]);

// Use the default value
$invoker->call(function ($name = 'world') {
    echo 'Hello ' . $name;
});

// Invoke any PHP callable
$invoker->call(['MyClass', 'myStaticMethod']);

// Using Class::method syntax
$invoker->call('MyClass::myStaticMethod');

Dependency injection in parameters is supported but needs to be configured with your container. Read on or jump to Built-in support for dependency injection if you are impatient., (*16)

Additionally, callables can also be resolved from your container. Read on or jump to Resolving callables from a container if you are impatient., (*17)

Parameter resolvers

Extending the behavior of the Invoker is easy and is done by implementing a ParameterResolver., (*18)

This is explained in details the Parameter resolvers documentation., (*19)

Built-in support for dependency injection

Rather than have you re-implement support for dependency injection with different containers every time, this package ships with 2 optional resolvers:, (*20)

  • TypeHintContainerResolver, (*21)

    This resolver will inject container entries by searching for the class name using the type-hint:, (*22)

    $invoker->call(function (Psr\Logger\LoggerInterface $logger) {
        // ...
    });
    

    In this example it will ->get('Psr\Logger\LoggerInterface') from the container and inject it., (*23)

    This resolver is only useful if you store objects in your container using the class (or interface) name. Silex or Symfony for example store services under a custom name (e.g. twig, db, etc.) instead of the class name: in that case use the resolver shown below., (*24)

  • ParameterNameContainerResolver, (*25)

    This resolver will inject container entries by searching for the name of the parameter:, (*26)

    $invoker->call(function ($twig) {
        // ...
    });
    

    In this example it will ->get('twig') from the container and inject it., (*27)

These resolvers can work with any dependency injection container compliant with PSR-11., (*28)

Setting up those resolvers is simple:, (*29)

// $container must be an instance of Psr\Container\ContainerInterface
$container = ...

$containerResolver = new TypeHintContainerResolver($container);
// or
$containerResolver = new ParameterNameContainerResolver($container);

$invoker = new Invoker\Invoker;
// Register it before all the other parameter resolvers
$invoker->getParameterResolver()->prependResolver($containerResolver);

You can also register both resolvers at the same time if you wish by prepending both. Implementing support for more tricky things is easy and up to you!, (*30)

Resolving callables from a container

The Invoker can be wired to your DI container to resolve the callables., (*31)

For example with an invokable class:, (*32)

class MyHandler
{
    public function __invoke()
    {
        // ...
    }
}

// By default this doesn't work: an instance of the class should be provided
$invoker->call('MyHandler');

// If we set up the container to use
$invoker = new Invoker\Invoker(null, $container);
// Now 'MyHandler' is resolved using the container!
$invoker->call('MyHandler');

The same works for a class method:, (*33)

class WelcomeController
{
    public function home()
    {
        // ...
    }
}

// By default this doesn't work: home() is not a static method
$invoker->call(['WelcomeController', 'home']);

// If we set up the container to use
$invoker = new Invoker\Invoker(null, $container);
// Now 'WelcomeController' is resolved using the container!
$invoker->call(['WelcomeController', 'home']);
// Alternatively we can use the Class::method syntax
$invoker->call('WelcomeController::home');

That feature can be used as the base building block for a framework's dispatcher., (*34)

Again, any PSR-11 compliant container can be provided., (*35)

The Versions

24/04 2015

dev-master

9999999-dev https://github.com/PHP-DI/Invoker

Generic and extensible callable invoker

  Sources   Download

MIT

The Requires

 

The Development Requires

callable dependency-injection dependency injection invoke invoker

24/04 2015

1.0.0

1.0.0.0 https://github.com/PHP-DI/Invoker

Generic and extensible callable invoker

  Sources   Download

MIT

The Requires

 

The Development Requires

callable dependency-injection dependency injection invoke invoker

01/04 2015

0.2.1

0.2.1.0 https://github.com/mnapoli/Invoker

Generic and extensible callable invoker

  Sources   Download

MIT

The Requires

 

The Development Requires

callable dependency-injection dependency injection invoke invoker

30/03 2015

0.2.0

0.2.0.0 https://github.com/mnapoli/Invoker

Generic and extensible callable invoker

  Sources   Download

MIT

The Requires

 

The Development Requires

callable dependency-injection dependency injection invoke invoker

22/03 2015

0.1.0

0.1.0.0 https://github.com/mnapoli/Invoker

Generic and extensible callable invoker

  Sources   Download

MIT

The Requires

 

The Development Requires

callable dependency-injection dependency injection invoke invoker