php-fn/invoker

通用且可扩展的可调用调用器

资助包维护!
mnapoli

dev-php-fn-master / 2.x-dev 2020-12-27 12:39 UTC

This package is auto-updated.

Last update: 2024-09-27 21:00:59 UTC


README

通用且可扩展的可调用调用器。

Build Status Latest Version Total Downloads

为什么?

谁不需要一个过度设计的 call_user_func()

命名参数

这个 Silex 示例看起来熟悉吗?

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

或者这个使用 Silly 定义的命令?

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

Slim 中也有同样的模式

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

你明白了。这些框架使用类似于命名参数的方式来调用控制器/命令/处理器:无论参数的顺序如何,它们都通过名称匹配。

这个库允许以通用和可扩展的方式调用带有命名参数的可调用项。

依赖注入

熟悉 AngularJS 的人都知道依赖注入是如何执行的

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

在 PHP 中,我们可以在一些框架和部分到完全支持的 DI 容器中再次找到这个模式。例如,在 Silex 中,您可以通过类型提示来获取应用程序以进行注入,但它只适用于 Silex\Application

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

在 Silly 中,它只适用于 OutputInterface 来注入应用程序输出

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

PHP-DI 提供了一种使用类型提示调用可调用项并从容器中解析所有依赖项的方法

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

这个库提供了清晰的扩展点,让框架实现他们想要的任何类型的依赖注入支持。

TL/DR

简而言之,这个库旨在成为调用具有命名参数和/或依赖注入的函数的基本构建块。

安装

$ composer require PHP-DI/invoker

用法

默认行为

默认情况下,Invoker 可以使用命名参数进行调用

$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');

参数中的依赖注入受支持,但需要使用您的容器进行配置。如果您迫不及待,请继续阅读或跳转到 内置的依赖注入支持

此外,可调用项也可以从您的容器中解析出来。如果您迫不及待,请继续阅读或跳转到 从容器解析可调用项

参数解析器

扩展 Invoker 的行为很简单,只需实现一个 ParameterResolver

这已经在 参数解析器文档 中详细说明。

内置的依赖注入支持

而不是让您每次都重新实现不同容器中的依赖注入支持,此软件包附带 2 个可选解析器

  • TypeHintContainerResolver

    此解析器将通过使用类型提示搜索类名来注入容器条目

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

    在这个例子中,它将从容器中 ->get('Psr\Logger\LoggerInterface') 并注入它。

    此解析器仅当您使用类(或接口)名称在容器中存储对象时才有用。例如,Silex 或 Symfony 将服务存储在自定义名称(例如 twigdb 等)下而不是类名:在这种情况下,请使用下面的解析器。

  • ParameterNameContainerResolver

    此解析器将通过搜索参数名称来注入容器条目

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

    在这个例子中,它将从容器中 ->get('twig') 并注入它。

这些解析器可以与任何符合 PSR-11 的依赖注入容器一起工作。

设置这些解析器很简单

// $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);

如果您愿意,也可以同时注册这两个解析器。实现对更复杂事物的支持也很容易,完全由您决定!

从容器中解析可调用对象

Invoker 可以连接到您的 DI 容器以解析可调用对象。

例如,对于一个可调用的类

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');

同样的方法也适用于类方法

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');

这个特性可以作为框架调度器的基础构建块。

再次强调,任何符合 PSR-11 的容器都可以提供。