PluginProbe
Admin Columns / 7.0.13
Admin Columns v7.0.13
7.1.4 7.0.19 2.3.5 2.4 2.4.1 2.4.10 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.6.1 2.5.6.2 2.5.6.3 2.5.6.4 3.0 3.0.1 All 113 releases
codepress-admin-columns / vendor / php-di / invoker / README.md
README.md
235 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 # Invoker
2
3 Generic and extensible callable invoker.
4
5 [](https://github.com/PHP-DI/Invoker/actions/workflows/ci.yml![CI](https://github.com/PHP-DI/Invoker/actions/workflows/ci.yml/badge.svg)](https://github.com/PHP-DI/Invoker/actions/workflows/ci.yml](https://github.com/PHP-DI/Invoker/actions/workflows/ci.yml)
6 [](https://packagist.org/packages/PHP-DI/invoker![Latest Version](https://img.shields.io/github/release/PHP-DI/invoker.svg?style=flat-square)](https://packagist.org/packages/PHP-DI/invoker](https://packagist.org/packages/PHP-DI/invoker)
7 [](https://packagist.org/packages/php-di/invoker![Total Downloads](https://img.shields.io/packagist/dt/php-di/invoker.svg?style=flat-square)](https://packagist.org/packages/php-di/invoker](https://packagist.org/packages/php-di/invoker)
8
9 ## Why?
10
11 Who doesn't need an over-engineered `call_user_func()`?
12
13 ### Named parameters
14
15 Does this [](https://github.com/silexphp/Silex#readmeSilex](https://github.com/silexphp/Silex#readme](https://github.com/silexphp/Silex#readme) example look familiar:
16
17 ```php
18 $app->get('/project/{project}/issue/{issue}', function ($project, $issue) {
19 // ...
20 });
21 ```
22
23 Or this command defined with [](https://github.com/mnapoli/silly#usageSilly](https://github.com/mnapoli/silly#usage](https://github.com/mnapoli/silly#usage):
24
25 ```php
26 $app->command('greet [name] [--yell]', function ($name, $yell) {
27 // ...
28 });
29 ```
30
31 Same pattern in [](https://www.slimframework.comSlim](https://www.slimframework.com](https://www.slimframework.com):
32
33 ```php
34 $app->get('/hello/:name', function ($name) {
35 // ...
36 });
37 ```
38
39 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.
40
41 **This library allows to invoke callables with named parameters in a generic and extensible way.**
42
43 ### Dependency injection
44
45 Anyone familiar with AngularJS is familiar with how dependency injection is performed:
46
47 ```js
48 angular.controller('MyController', ['dep1', 'dep2', function(dep1, dep2) {
49 // ...
50 }]);
51 ```
52
53 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`:
54
55 ```php
56 $app->get('/hello/{name}', function (Silex\Application $app, $name) {
57 // ...
58 });
59 ```
60
61 In Silly, it only works with `OutputInterface` to inject the application output:
62
63 ```php
64 $app->command('greet [name]', function ($name, OutputInterface $output) {
65 // ...
66 });
67 ```
68
69 [](https://php-di.org/doc/container.htmlPHP-DI](https://php-di.org/doc/container.html](https://php-di.org/doc/container.html) provides a way to invoke a callable and resolve all dependencies from the container using type-hints:
70
71 ```php
72 $container->call(function (Logger $logger, EntityManager $em) {
73 // ...
74 });
75 ```
76
77 **This library provides clear extension points to let frameworks implement any kind of dependency injection support they want.**
78
79 ### TL/DR
80
81 In short, this library is meant to be a base building block for calling a function with named parameters and/or dependency injection.
82
83 ## Installation
84
85 ```sh
86 $ composer require PHP-DI/invoker
87 ```
88
89 ## Usage
90
91 ### Default behavior
92
93 By default the `Invoker` can call using named parameters:
94
95 ```php
96 $invoker = new Invoker\Invoker;
97
98 $invoker->call(function () {
99 echo 'Hello world!';
100 });
101
102 // Simple parameter array
103 $invoker->call(function ($name) {
104 echo 'Hello ' . $name;
105 }, ['John']);
106
107 // Named parameters
108 $invoker->call(function ($name) {
109 echo 'Hello ' . $name;
110 }, [
111 'name' => 'John'
112 ]);
113
114 // Use the default value
115 $invoker->call(function ($name = 'world') {
116 echo 'Hello ' . $name;
117 });
118
119 // Invoke any PHP callable
120 $invoker->call(['MyClass', 'myStaticMethod']);
121
122 // Using Class::method syntax
123 $invoker->call('MyClass::myStaticMethod');
124 ```
125
126 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*Built-in support for dependency injection*](#built-in-support-for-dependency-injection](#built-in-support-for-dependency-injection) if you are impatient.
127
128 Additionally, callables can also be resolved from your container. Read on or jump to [](#resolving-callables-from-a-container*Resolving callables from a container*](#resolving-callables-from-a-container](#resolving-callables-from-a-container) if you are impatient.
129
130 ### Parameter resolvers
131
132 Extending the behavior of the `Invoker` is easy and is done by implementing a [](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php`ParameterResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php).
133
134 This is explained in details the [](doc/parameter-resolvers.mdParameter resolvers documentation](doc/parameter-resolvers.md](doc/parameter-resolvers.md).
135
136 #### Built-in support for dependency injection
137
138 Rather than have you re-implement support for dependency injection with different containers every time, this package ships with 2 optional resolvers:
139
140 - [](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/TypeHintContainerResolver.php`TypeHintContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/TypeHintContainerResolver.php](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/TypeHintContainerResolver.php)
141
142 This resolver will inject container entries by searching for the class name using the type-hint:
143
144 ```php
145 $invoker->call(function (Psr\Logger\LoggerInterface $logger) {
146 // ...
147 });
148 ```
149
150 In this example it will `->get('Psr\Logger\LoggerInterface')` from the container and inject it.
151
152 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.
153
154 - [`ParameterNameContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/ParameterNameContainerResolver.php)
155
156 This resolver will inject container entries by searching for the name of the parameter:
157
158 ```php
159 $invoker->call(function ($twig) {
160 // ...
161 });
162 ```
163
164 In this example it will `->get('twig')` from the container and inject it.
165
166 These resolvers can work with any dependency injection container compliant with [PSR-11](http://www.php-fig.org/psr/psr-11/).
167
168 Setting up those resolvers is simple:
169
170 ```php
171 // $container must be an instance of Psr\Container\ContainerInterface
172 $container = ...
173
174 $containerResolver = new TypeHintContainerResolver($container);
175 // or
176 $containerResolver = new ParameterNameContainerResolver($container);
177
178 $invoker = new Invoker\Invoker;
179 // Register it before all the other parameter resolvers
180 $invoker->getParameterResolver()->prependResolver($containerResolver);
181 ```
182
183 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!
184
185 ### Resolving callables from a container
186
187 The `Invoker` can be wired to your DI container to resolve the callables.
188
189 For example with an invokable class:
190
191 ```php
192 class MyHandler
193 {
194 public function __invoke()
195 {
196 // ...
197 }
198 }
199
200 // By default this doesn't work: an instance of the class should be provided
201 $invoker->call('MyHandler');
202
203 // If we set up the container to use
204 $invoker = new Invoker\Invoker(null, $container);
205 // Now 'MyHandler' is resolved using the container!
206 $invoker->call('MyHandler');
207 ```
208
209 The same works for a class method:
210
211 ```php
212 class WelcomeController
213 {
214 public function home()
215 {
216 // ...
217 }
218 }
219
220 // By default this doesn't work: home() is not a static method
221 $invoker->call(['WelcomeController', 'home']);
222
223 // If we set up the container to use
224 $invoker = new Invoker\Invoker(null, $container);
225 // Now 'WelcomeController' is resolved using the container!
226 $invoker->call(['WelcomeController', 'home']);
227 // Alternatively we can use the Class::method syntax
228 $invoker->call('WelcomeController::home');
229 ```
230
231 That feature can be used as the base building block for a framework's dispatcher.
232
233 Again, any [PSR-11](https://www.php-fig.org/psr/psr-11/) compliant container can be provided.
234
235