Файловый менеджер - Редактировать - /home/tuudkjt/globeasy/wp-includes/ID3/invoker.tar
Назад
composer.json 0000777 00000001637 15251240124 0007300 0 ustar 00 { "name": "php-di\/invoker", "description": "Generic and extensible callable invoker", "keywords": [ "invoker", "dependency-injection", "dependency", "injection", "callable", "invoke" ], "homepage": "https:\/\/github.com\/PHP-DI\/Invoker", "license": "MIT", "type": "library", "autoload": { "psr-4": { "Rvx\\Invoker\\": "src\/" } }, "autoload-dev": { "psr-4": { "Rvx\\Invoker\\Test\\": "tests\/" } }, "require": { "php": ">=7.3", "psr\/container": "^1.0|^2.0" }, "require-dev": { "phpunit\/phpunit": "^9.0 || ^10 || ^11 || ^12", "athletic\/athletic": "~0.1.8", "mnapoli\/hard-mode": "~0.3.0" }, "config": { "allow-plugins": { "dealerdirect\/phpcodesniffer-composer-installer": true } } } src/InvokerInterface.php 0000777 00000001346 15251240124 0011311 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker; use Rvx\Invoker\Exception\InvocationException; use Rvx\Invoker\Exception\NotCallableException; use Rvx\Invoker\Exception\NotEnoughParametersException; /** * Invoke a callable. */ interface InvokerInterface { /** * Call the given function using the given parameters. * * @param callable|array|string $callable Function to call. * @param array $parameters Parameters to use. * @return mixed Result of the function. * @throws InvocationException Base exception class for all the sub-exceptions below. * @throws NotCallableException * @throws NotEnoughParametersException */ public function call($callable, array $parameters = []); } src/CallableResolver.php 0000777 00000007076 15251240124 0011302 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker; use Closure; use Rvx\Invoker\Exception\NotCallableException; use Rvx\Psr\Container\ContainerInterface; use Rvx\Psr\Container\NotFoundExceptionInterface; use ReflectionException; use ReflectionMethod; /** * Resolves a callable from a container. */ class CallableResolver { /** @var ContainerInterface */ private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } /** * Resolve the given callable into a real PHP callable. * * @param callable|string|array $callable * @return callable Real PHP callable. * @throws NotCallableException|ReflectionException */ public function resolve($callable) : callable { if (\is_string($callable) && \strpos($callable, '::') !== \false) { $callable = \explode('::', $callable, 2); } $callable = $this->resolveFromContainer($callable); if (!\is_callable($callable)) { throw NotCallableException::fromInvalidCallable($callable, \true); } return $callable; } /** * @param callable|string|array $callable * @return callable|mixed * @throws NotCallableException|ReflectionException */ private function resolveFromContainer($callable) { // Shortcut for a very common use case if ($callable instanceof Closure) { return $callable; } // If it's already a callable there is nothing to do if (\is_callable($callable)) { // TODO with PHP 8 that should not be necessary to check this anymore if (!$this->isStaticCallToNonStaticMethod($callable)) { return $callable; } } // The callable is a container entry name if (\is_string($callable)) { try { return $this->container->get($callable); } catch (NotFoundExceptionInterface $e) { if ($this->container->has($callable)) { throw $e; } throw NotCallableException::fromInvalidCallable($callable, \true); } } // The callable is an array whose first item is a container entry name // e.g. ['some-container-entry', 'methodToCall'] if (\is_array($callable) && \is_string($callable[0])) { try { // Replace the container entry name by the actual object $callable[0] = $this->container->get($callable[0]); return $callable; } catch (NotFoundExceptionInterface $e) { if ($this->container->has($callable[0])) { throw $e; } throw new NotCallableException(\sprintf('Cannot call %s() on %s because it is not a class nor a valid container entry', $callable[1], $callable[0])); } } // Unrecognized stuff, we let it fail later return $callable; } /** * Check if the callable represents a static call to a non-static method. * * @param mixed $callable * @throws ReflectionException */ private function isStaticCallToNonStaticMethod($callable) : bool { if (\is_array($callable) && \is_string($callable[0])) { [$class, $method] = $callable; if (!\method_exists($class, $method)) { return \false; } $reflection = new ReflectionMethod($class, $method); return !$reflection->isStatic(); } return \false; } } src/Reflection/CallableReflection.php 0000777 00000003024 15251240124 0013652 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\Reflection; use Closure; use Rvx\Invoker\Exception\NotCallableException; use ReflectionException; use ReflectionFunction; use ReflectionFunctionAbstract; use ReflectionMethod; /** * Create a reflection object from a callable or a callable-like. * * @internal */ class CallableReflection { /** * @param callable|array|string $callable Can be a callable or a callable-like. * @throws NotCallableException|ReflectionException */ public static function create($callable) : ReflectionFunctionAbstract { // Closure if ($callable instanceof Closure) { return new ReflectionFunction($callable); } // Array callable if (\is_array($callable)) { [$class, $method] = $callable; if (!\method_exists($class, $method)) { throw NotCallableException::fromInvalidCallable($callable); } return new ReflectionMethod($class, $method); } // Callable object (i.e. implementing __invoke()) if (\is_object($callable) && \method_exists($callable, '__invoke')) { return new ReflectionMethod($callable, '__invoke'); } // Standard function if (\is_string($callable) && \function_exists($callable)) { return new ReflectionFunction($callable); } throw new NotCallableException(\sprintf('%s is not a callable', \is_string($callable) ? $callable : 'Instance of ' . \get_class($callable))); } } src/Exception/NotEnoughParametersException.php 0000777 00000000321 15251240124 0015612 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\Exception; /** * Not enough parameters could be resolved to invoke the callable. */ class NotEnoughParametersException extends InvocationException { } src/Exception/NotCallableException.php 0000777 00000002212 15251240124 0014041 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\Exception; /** * The given callable is not actually callable. */ class NotCallableException extends InvocationException { /** * @param mixed $value */ public static function fromInvalidCallable($value, bool $containerEntry = \false) : self { if (\is_object($value)) { $message = \sprintf('Instance of %s is not a callable', \get_class($value)); } elseif (\is_array($value) && isset($value[0], $value[1])) { $class = \is_object($value[0]) ? \get_class($value[0]) : $value[0]; $extra = \method_exists($class, '__call') || \method_exists($class, '__callStatic') ? ' A __call() or __callStatic() method exists but magic methods are not supported.' : ''; $message = \sprintf('%s::%s() is not a callable.%s', $class, $value[1], $extra); } elseif ($containerEntry) { $message = \var_export($value, \true) . ' is neither a callable nor a valid container entry'; } else { $message = \var_export($value, \true) . ' is not a callable'; } return new self($message); } } src/Exception/InvocationException.php 0000777 00000000242 15251240124 0013773 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\Exception; /** * Impossible to invoke the callable. */ class InvocationException extends \Exception { } src/Invoker.php 0000777 00000006232 15251240124 0007467 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker; use Rvx\Invoker\Exception\NotCallableException; use Rvx\Invoker\Exception\NotEnoughParametersException; use Rvx\Invoker\ParameterResolver\AssociativeArrayResolver; use Rvx\Invoker\ParameterResolver\DefaultValueResolver; use Rvx\Invoker\ParameterResolver\NumericArrayResolver; use Rvx\Invoker\ParameterResolver\ParameterResolver; use Rvx\Invoker\ParameterResolver\ResolverChain; use Rvx\Invoker\Reflection\CallableReflection; use Rvx\Psr\Container\ContainerInterface; use ReflectionParameter; /** * Invoke a callable. */ class Invoker implements InvokerInterface { /** @var CallableResolver|null */ private $callableResolver; /** @var ParameterResolver */ private $parameterResolver; /** @var ContainerInterface|null */ private $container; public function __construct(?ParameterResolver $parameterResolver = null, ?ContainerInterface $container = null) { $this->parameterResolver = $parameterResolver ?: $this->createParameterResolver(); $this->container = $container; if ($container) { $this->callableResolver = new CallableResolver($container); } } /** * {@inheritdoc} */ public function call($callable, array $parameters = []) { if ($this->callableResolver) { $callable = $this->callableResolver->resolve($callable); } if (!\is_callable($callable)) { throw new NotCallableException(\sprintf('%s is not a callable', \is_object($callable) ? 'Instance of ' . \get_class($callable) : \var_export($callable, \true))); } $callableReflection = CallableReflection::create($callable); $args = $this->parameterResolver->getParameters($callableReflection, $parameters, []); // Sort by array key because call_user_func_array ignores numeric keys \ksort($args); // Check all parameters are resolved $diff = \array_diff_key($callableReflection->getParameters(), $args); $parameter = \reset($diff); if ($parameter && \assert($parameter instanceof ReflectionParameter) && !$parameter->isVariadic()) { throw new NotEnoughParametersException(\sprintf('Unable to invoke the callable because no value was given for parameter %d ($%s)', $parameter->getPosition() + 1, $parameter->name)); } return \call_user_func_array($callable, $args); } /** * Create the default parameter resolver. */ private function createParameterResolver() : ParameterResolver { return new ResolverChain([new NumericArrayResolver(), new AssociativeArrayResolver(), new DefaultValueResolver()]); } /** * @return ParameterResolver By default it's a ResolverChain */ public function getParameterResolver() : ParameterResolver { return $this->parameterResolver; } public function getContainer() : ?ContainerInterface { return $this->container; } /** * @return CallableResolver|null Returns null if no container was given in the constructor. */ public function getCallableResolver() : ?CallableResolver { return $this->callableResolver; } } src/ParameterResolver/Container/TypeHintContainerResolver.php 0000777 00000003574 15251240124 0020575 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\ParameterResolver\Container; use Rvx\Invoker\ParameterResolver\ParameterResolver; use Rvx\Psr\Container\ContainerInterface; use ReflectionFunctionAbstract; use ReflectionNamedType; /** * Inject entries from a DI container using the type-hints. */ class TypeHintContainerResolver implements ParameterResolver { /** @var ContainerInterface */ private $container; /** * @param ContainerInterface $container The container to get entries from. */ public function __construct(ContainerInterface $container) { $this->container = $container; } public function getParameters(ReflectionFunctionAbstract $reflection, array $providedParameters, array $resolvedParameters) : array { $parameters = $reflection->getParameters(); // Skip parameters already resolved if (!empty($resolvedParameters)) { $parameters = \array_diff_key($parameters, $resolvedParameters); } foreach ($parameters as $index => $parameter) { $parameterType = $parameter->getType(); if (!$parameterType) { // No type continue; } if (!$parameterType instanceof ReflectionNamedType) { // Union types are not supported continue; } if ($parameterType->isBuiltin()) { // Primitive types are not supported continue; } $parameterClass = $parameterType->getName(); if ($parameterClass === 'self') { $parameterClass = $parameter->getDeclaringClass()->getName(); } if ($this->container->has($parameterClass)) { $resolvedParameters[$index] = $this->container->get($parameterClass); } } return $resolvedParameters; } } src/ParameterResolver/Container/ParameterNameContainerResolver.php 0000777 00000002404 15251240124 0021541 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\ParameterResolver\Container; use Rvx\Invoker\ParameterResolver\ParameterResolver; use Rvx\Psr\Container\ContainerInterface; use ReflectionFunctionAbstract; /** * Inject entries from a DI container using the parameter names. */ class ParameterNameContainerResolver implements ParameterResolver { /** @var ContainerInterface */ private $container; /** * @param ContainerInterface $container The container to get entries from. */ public function __construct(ContainerInterface $container) { $this->container = $container; } public function getParameters(ReflectionFunctionAbstract $reflection, array $providedParameters, array $resolvedParameters) : array { $parameters = $reflection->getParameters(); // Skip parameters already resolved if (!empty($resolvedParameters)) { $parameters = \array_diff_key($parameters, $resolvedParameters); } foreach ($parameters as $index => $parameter) { $name = $parameter->name; if ($name && $this->container->has($name)) { $resolvedParameters[$index] = $this->container->get($name); } } return $resolvedParameters; } } src/ParameterResolver/AssociativeArrayResolver.php 0000777 00000002075 15251240124 0016510 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\ParameterResolver; use ReflectionFunctionAbstract; /** * Tries to map an associative array (string-indexed) to the parameter names. * * E.g. `->call($callable, ['foo' => 'bar'])` will inject the string `'bar'` * in the parameter named `$foo`. * * Parameters that are not indexed by a string are ignored. */ class AssociativeArrayResolver implements ParameterResolver { public function getParameters(ReflectionFunctionAbstract $reflection, array $providedParameters, array $resolvedParameters) : array { $parameters = $reflection->getParameters(); // Skip parameters already resolved if (!empty($resolvedParameters)) { $parameters = \array_diff_key($parameters, $resolvedParameters); } foreach ($parameters as $index => $parameter) { if (\array_key_exists($parameter->name, $providedParameters)) { $resolvedParameters[$index] = $providedParameters[$parameter->name]; } } return $resolvedParameters; } } src/ParameterResolver/TypeHintResolver.php 0000777 00000003063 15251240124 0015001 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\ParameterResolver; use ReflectionFunctionAbstract; use ReflectionNamedType; /** * Inject entries using type-hints. * * Tries to match type-hints with the parameters provided. */ class TypeHintResolver implements ParameterResolver { public function getParameters(ReflectionFunctionAbstract $reflection, array $providedParameters, array $resolvedParameters) : array { $parameters = $reflection->getParameters(); // Skip parameters already resolved if (!empty($resolvedParameters)) { $parameters = \array_diff_key($parameters, $resolvedParameters); } foreach ($parameters as $index => $parameter) { $parameterType = $parameter->getType(); if (!$parameterType) { // No type continue; } if (!$parameterType instanceof ReflectionNamedType) { // Union types are not supported continue; } if ($parameterType->isBuiltin()) { // Primitive types are not supported continue; } $parameterClass = $parameterType->getName(); if ($parameterClass === 'self') { $parameterClass = $parameter->getDeclaringClass()->getName(); } if (\array_key_exists($parameterClass, $providedParameters)) { $resolvedParameters[$index] = $providedParameters[$parameterClass]; } } return $resolvedParameters; } } src/ParameterResolver/ResolverChain.php 0000777 00000003001 15251240124 0014247 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\ParameterResolver; use ReflectionFunctionAbstract; /** * Dispatches the call to other resolvers until all parameters are resolved. * * Chain of responsibility pattern. */ class ResolverChain implements ParameterResolver { /** @var ParameterResolver[] */ private $resolvers; public function __construct(array $resolvers = []) { $this->resolvers = $resolvers; } public function getParameters(ReflectionFunctionAbstract $reflection, array $providedParameters, array $resolvedParameters) : array { $reflectionParameters = $reflection->getParameters(); foreach ($this->resolvers as $resolver) { $resolvedParameters = $resolver->getParameters($reflection, $providedParameters, $resolvedParameters); $diff = \array_diff_key($reflectionParameters, $resolvedParameters); if (empty($diff)) { // Stop traversing: all parameters are resolved return $resolvedParameters; } } return $resolvedParameters; } /** * Push a parameter resolver after the ones already registered. */ public function appendResolver(ParameterResolver $resolver) : void { $this->resolvers[] = $resolver; } /** * Insert a parameter resolver before the ones already registered. */ public function prependResolver(ParameterResolver $resolver) : void { \array_unshift($this->resolvers, $resolver); } } src/ParameterResolver/DefaultValueResolver.php 0000777 00000002511 15251240124 0015613 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\ParameterResolver; use ReflectionException; use ReflectionFunctionAbstract; /** * Finds the default value for a parameter, *if it exists*. */ class DefaultValueResolver implements ParameterResolver { public function getParameters(ReflectionFunctionAbstract $reflection, array $providedParameters, array $resolvedParameters) : array { $parameters = $reflection->getParameters(); // Skip parameters already resolved if (!empty($resolvedParameters)) { $parameters = \array_diff_key($parameters, $resolvedParameters); } foreach ($parameters as $index => $parameter) { \assert($parameter instanceof \ReflectionParameter); if ($parameter->isDefaultValueAvailable()) { try { $resolvedParameters[$index] = $parameter->getDefaultValue(); } catch (ReflectionException $e) { // Can't get default values from PHP internal classes and functions } } else { $parameterType = $parameter->getType(); if ($parameterType && $parameterType->allowsNull()) { $resolvedParameters[$index] = null; } } } return $resolvedParameters; } } src/ParameterResolver/ParameterResolver.php 0000777 00000001662 15251240124 0015160 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\ParameterResolver; use ReflectionFunctionAbstract; /** * Resolves the parameters to use to call the callable. */ interface ParameterResolver { /** * Resolves the parameters to use to call the callable. * * `$resolvedParameters` contains parameters that have already been resolved. * * Each ParameterResolver must resolve parameters that are not already * in `$resolvedParameters`. That allows to chain multiple ParameterResolver. * * @param ReflectionFunctionAbstract $reflection Reflection object for the callable. * @param array $providedParameters Parameters provided by the caller. * @param array $resolvedParameters Parameters resolved (indexed by parameter position). * @return array */ public function getParameters(ReflectionFunctionAbstract $reflection, array $providedParameters, array $resolvedParameters); } src/ParameterResolver/NumericArrayResolver.php 0000777 00000002027 15251240124 0015635 0 ustar 00 <?php declare (strict_types=1); namespace Rvx\Invoker\ParameterResolver; use ReflectionFunctionAbstract; /** * Simply returns all the values of the $providedParameters array that are * indexed by the parameter position (i.e. a number). * * E.g. `->call($callable, ['foo', 'bar'])` will simply resolve the parameters * to `['foo', 'bar']`. * * Parameters that are not indexed by a number (i.e. parameter position) * will be ignored. */ class NumericArrayResolver implements ParameterResolver { public function getParameters(ReflectionFunctionAbstract $reflection, array $providedParameters, array $resolvedParameters) : array { // Skip parameters already resolved if (!empty($resolvedParameters)) { $providedParameters = \array_diff_key($providedParameters, $resolvedParameters); } foreach ($providedParameters as $key => $value) { if (\is_int($key)) { $resolvedParameters[$key] = $value; } } return $resolvedParameters; } } README.md 0000777 00000016212 15251240124 0006030 0 ustar 00 # Invoker Generic and extensible callable invoker. [](https://github.com/PHP-DI/Invoker/actions/workflows/ci.yml) [](https://packagist.org/packages/PHP-DI/invoker) [](https://packagist.org/packages/php-di/invoker) ## Why? Who doesn't need an over-engineered `call_user_func()`? ### Named parameters Does this [Silex](https://github.com/silexphp/Silex#readme) example look familiar: ```php $app->get('/project/{project}/issue/{issue}', function ($project, $issue) { // ... }); ``` Or this command defined with [Silly](https://github.com/mnapoli/silly#usage): ```php $app->command('greet [name] [--yell]', function ($name, $yell) { // ... }); ``` Same pattern in [Slim](https://www.slimframework.com): ```php $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: ```js 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`: ```php $app->get('/hello/{name}', function (Silex\Application $app, $name) { // ... }); ``` In Silly, it only works with `OutputInterface` to inject the application output: ```php $app->command('greet [name]', function ($name, OutputInterface $output) { // ... }); ``` [PHP-DI](https://php-di.org/doc/container.html) provides a way to invoke a callable and resolve all dependencies from the container using type-hints: ```php $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 ```sh $ composer require PHP-DI/invoker ``` ## Usage ### Default behavior By default the `Invoker` can call using named parameters: ```php $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*](#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*](#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`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php). This is explained in details the [Parameter resolvers documentation](doc/parameter-resolvers.md). #### 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`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/TypeHintContainerResolver.php) This resolver will inject container entries by searching for the class name using the type-hint: ```php $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`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/ParameterNameContainerResolver.php) This resolver will inject container entries by searching for the name of the parameter: ```php $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](http://www.php-fig.org/psr/psr-11/). Setting up those resolvers is simple: ```php // $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: ```php 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: ```php 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](https://www.php-fig.org/psr/psr-11/) compliant container can be provided. LICENSE 0000777 00000002065 15251240124 0005557 0 ustar 00 The MIT License (MIT) Copyright (c) Matthieu Napoli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
| ver. 1.6 |
Github
|
.
| PHP 8.1.34 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка