All Projects → PHP-DI → Invoker

PHP-DI / Invoker

Licence: mit
Generic and extensible callable invoker

Projects that are alternatives of or similar to Invoker

Declex
DecleX - Declarative Framework for Android, easier and faster coding.
Stars: ✭ 174 (-24.02%)
Mutual labels:  dependency-injection
Reto
Flexible and efficient React Store with hooks.
Stars: ✭ 194 (-15.28%)
Mutual labels:  dependency-injection
Pimple
A small PHP dependency injection container
Stars: ✭ 2,491 (+987.77%)
Mutual labels:  dependency-injection
Katana
Lightweight, minimalistic dependency injection library for Kotlin & Android
Stars: ✭ 181 (-20.96%)
Mutual labels:  dependency-injection
Arouter
💪 A framework for assisting in the renovation of Android componentization (帮助 Android App 进行组件化改造的路由框架)
Stars: ✭ 13,587 (+5833.19%)
Mutual labels:  dependency-injection
Typedi
Simple yet powerful dependency injection tool for JavaScript and TypeScript.
Stars: ✭ 2,832 (+1136.68%)
Mutual labels:  dependency-injection
Ioc
🦄 lightweight (<1kb) inversion of control javascript library for dependency injection written in typescript
Stars: ✭ 171 (-25.33%)
Mutual labels:  dependency-injection
Transfuse
💉 Transfuse - A Dependency Injection and Integration framework for Google Android
Stars: ✭ 226 (-1.31%)
Mutual labels:  dependency-injection
Malagu
Malagu is a Serverless First, component-based, platform-independent, progressive application framework based on TypeScript.
Stars: ✭ 184 (-19.65%)
Mutual labels:  dependency-injection
Swinjectstoryboard
Swinject extension for automatic dependency injection via Storyboard
Stars: ✭ 211 (-7.86%)
Mutual labels:  dependency-injection
Php Di
The dependency injection container for humans
Stars: ✭ 2,273 (+892.58%)
Mutual labels:  dependency-injection
Reactant
A framework for building React applications
Stars: ✭ 185 (-19.21%)
Mutual labels:  dependency-injection
Testdeck
Object oriented testing
Stars: ✭ 206 (-10.04%)
Mutual labels:  dependency-injection
Ray.di
Guice style dependency injection framework for PHP
Stars: ✭ 175 (-23.58%)
Mutual labels:  dependency-injection
Coldbox Platform
A modern, fluent and conventions based HMVC framework for ColdFusion (CFML)
Stars: ✭ 220 (-3.93%)
Mutual labels:  dependency-injection
Magnet
Dependency injection for modular Android applications
Stars: ✭ 173 (-24.45%)
Mutual labels:  dependency-injection
Koin Samples
KOIN - a concise and pragmatic dependency injection framework for Kotlin -- #Samples
Stars: ✭ 200 (-12.66%)
Mutual labels:  dependency-injection
Dry System
Organize your code into reusable components
Stars: ✭ 228 (-0.44%)
Mutual labels:  dependency-injection
Angular Awesome List
Список ресурсов по Angular на русском
Stars: ✭ 224 (-2.18%)
Mutual labels:  dependency-injection
Inversify Express Example
The official express + inversify+ inversify-express-utils examples
Stars: ✭ 210 (-8.3%)
Mutual labels:  dependency-injection

Invoker

Generic and extensible callable invoker.

Build Status Latest Version Total Downloads

Why?

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

Named parameters

Does this Silex example look familiar:

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

Or this command defined with Silly:

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

Same pattern in Slim:

$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.

This library allows to invoke callables with named parameters in a generic and extensible way.

Dependency injection

Anyone familiar with AngularJS is familiar with how dependency injection is performed:

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:

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

In Silly, it only works with OutputInterface to inject the application output:

$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:

$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.

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.

Installation

$ composer require PHP-DI/invoker

Usage

Default behavior

By default the Invoker can call using named parameters:

$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.

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

Parameter resolvers

Extending the behavior of the Invoker is easy and is done by implementing a ParameterResolver.

This is explained in details the Parameter resolvers documentation.

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:

  • TypeHintContainerResolver

    This resolver will inject container entries by searching for the class name using the type-hint:

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

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

    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.

  • ParameterNameContainerResolver

    This resolver will inject container entries by searching for the name of the parameter:

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

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

These resolvers can work with any dependency injection container compliant with PSR-11.

Setting up those resolvers is simple:

// $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!

Resolving callables from a container

The Invoker can be wired to your DI container to resolve the callables.

For example with an invokable class:

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:

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.

Again, any PSR-11 compliant container can be provided.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].