mnapoli / invoker
Requires
- php: >=7.3
- psr/container: ^1.0|^2.0
Requires (Dev)
- athletic/athletic: ~0.1.8
- mnapoli/hard-mode: ~0.3.0
- phpunit/phpunit: ^9.0
README
通用且可扩展的调用者。
为什么?
谁不需要一个过度设计的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个可选解析器
-
这个解析器将通过使用类型提示搜索类名来注入容器条目
$invoker->call(function (Psr\Logger\LoggerInterface $logger) { // ... });
在这个例子中,它将从容器中获取
->get('Psr\Logger\LoggerInterface')
并注入它。此解析器仅在您使用类(或接口)名称在容器中存储对象时才有用。例如,Silex 或 Symfony 会将服务存储在自定义名称(例如
twig
、db
等)下,而不是类名:在这种情况下,请使用下面的解析器。 -
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 的容器都可以提供。