花粉解决方案 / 参数解析器
花粉解决方案 - 参数解析组件 - 可调用对象的智能参数解析
v1.0.2
2022-04-16 00:00 UTC
Requires
- php: ^7.4 || ^8.0
Requires (Dev)
- phpunit/phpunit: ^9.0
- roave/security-advisories: dev-latest
Suggests
- pollen-solutions/container: Pollen Solutions - Container Component - PSR-11 ready Dependencies Injection Container.
- pollen-solutions/http: Pollen Http Component - HTTP specification layer.
This package is auto-updated.
Last update: 2024-09-04 16:40:03 UTC
README
花粉解决方案的 参数解析器 组件是一个可调用对象的智能参数解析库。它允许您动态确定要传递给函数、可调用的类或方法的参数。
安装
composer require pollen-solutions/argument-resolver
基本用法
use Pollen\ArgumentResolver\ArgumentResolver; use Pollen\ArgumentResolver\Resolvers\ParameterResolver; $acmeCallable = static function (int $product_id, string $name, bool $in_stock, float $price, array $product_attrs) { var_dump($product_id, $in_stock, $price, $product_attrs); exit; }; $parameters = [ 'product_id' => 1, 'name' => 'My beautiful sneaker', 'in_stock' => true, 'price' => 156.30, 'product_attrs' => [ 'size' => 12, 'color' => 'pink' ] ]; $arguments = (new ArgumentResolver([new ParameterResolver($parameters)]))->resolve($acmeCallable); $acmeCallable(...$arguments);
以下示例中,可调用对象是一个闭包函数。
它也可以是一个类方法
use Pollen\ArgumentResolver\ArgumentResolver; use Pollen\ArgumentResolver\Resolvers\ParameterResolver; class AcmeClass { public function storeProduct(int $product_id, string $name, bool $in_stock, float $price, array $product_attrs) { var_dump($product_id, $in_stock, $price, $product_attrs); exit; } } $acmeCallable = [new AcmeClass(), 'storeProduct']; $parameters = [ 'product_id' => 1, 'name' => 'My beautiful sneaker', 'in_stock' => true, 'price' => 156.30, 'product_attrs' => [ 'size' => 12, 'color' => 'pink' ] ]; $arguments = (new ArgumentResolver([new ParameterResolver($parameters)]))->resolve($acmeCallable); $acmeCallable(...$arguments);
此外,它还可以是一个可调用的类
use Pollen\ArgumentResolver\ArgumentResolver; use Pollen\ArgumentResolver\Resolvers\ParameterResolver; class AcmeClass { public function __invoke(int $product_id, string $name, bool $in_stock, float $price, array $product_attrs) { var_dump($product_id, $in_stock, $price, $product_attrs); exit; } } $acmeCallable = new AcmeClass(); $parameters = [ 'product_id' => 1, 'name' => 'My beautiful sneaker', 'in_stock' => true, 'price' => 156.30, 'product_attrs' => [ 'size' => 12, 'color' => 'pink' ] ]; $arguments = (new ArgumentResolver([new ParameterResolver($parameters)]))->resolve($acmeCallable); $acmeCallable(...$arguments);
解析器
参数解析器
-- @todo 或见下文 --
容器解析器
容器解析器用于解析由实现 \Psr\Container\ContainerInterface 的容器提供的可调用参数。
use Pollen\Container\Container; use Pollen\ArgumentResolver\ArgumentResolver; use Pollen\ArgumentResolver\Resolvers\ContainerResolver; class Foo {} class Bar {} $container = new Container(); $container->add(Foo::class, new Foo); $container->add(Bar::class, new Bar); $acmeCallable = static function (Foo $foo, Bar $bar) { var_dump($foo, $bar); exit; }; $arguments = (new ArgumentResolver([new ContainerResolver($container)]))->resolve($acmeCallable); $acmeCallable(...$arguments);
请求解析器
请求解析器用于解析由实现 Psr\Http\Message\ServerRequestInterface 的 HTTP 请求提供的可调用参数。
use Laminas\Diactoros\ServerRequestFactory; use Pollen\ArgumentResolver\ArgumentResolver; use Pollen\ArgumentResolver\Resolvers\RequestResolver; // This code must be served by your app and visits : // http://127.0.0.1/?product_id=1&name=My beautiful sneaker&in_stock=true&price=156.30&product_attrs[size]=12&product_attrs[color]=pink $request = ServerRequestFactory::fromGlobals(); // also you can force $_GET attributes : //$request = ServerRequestFactory::fromGlobals(null, [ // 'product_id' => 1, // 'name' => 'My beautiful sneaker', // 'in_stock' => true, // 'price' => 156.30, // 'product_attrs' => [ // 'size' => 12, // 'color' => 'pink' // ] //]); $acmeCallable = static function (int $product_id, string $name, bool $in_stock, float $price, array $product_attrs) { var_dump($product_id, $in_stock, $price, $product_attrs); exit; }; $arguments = (new ArgumentResolver([new RequestResolver($request)]))->resolve($acmeCallable); $acmeCallable(...$arguments);
请求属性解析器
请求属性解析器用于解析通过实现 Psr\Http\Message\ServerRequestInterface 的 HTTP 请求属性提供的可调用参数。
use Laminas\Diactoros\ServerRequestFactory; use Pollen\ArgumentResolver\ArgumentResolver; use Pollen\ArgumentResolver\Resolvers\RequestAttributeResolver; $request = ServerRequestFactory::fromGlobals(); $request = $request->withAttribute('product_id', 1); $request = $request->withAttribute('name', 'My beautiful sneaker'); $request = $request->withAttribute('in_stock', true); $request = $request->withAttribute('price', 156.30); $request = $request->withAttribute('filters', [ 'size' => 12, 'color' => 'pink' ]); $acmeCallable = static function (int $product_id, string $name, bool $in_stock, float $price, array $product_attrs) { var_dump($product_id, $in_stock, $price, $product_attrs); exit; }; $arguments = (new ArgumentResolver([new RequestAttributeResolver($request)]))->resolve($acmeCallable); $acmeCallable(...$arguments);
链式解析器
use Pollen\Container\Container; use Pollen\ArgumentResolver\ArgumentResolver; use Pollen\ArgumentResolver\Resolvers\ContainerResolver; use Pollen\ArgumentResolver\Resolvers\ParameterResolver; class EntityManager {} $container = new Container(); $container->add(EntityManager::class, new EntityManager); $acmeCallable = static function (EntityManager $manager, int $product_id, string $name, bool $in_stock, float $price, array $product_attrs) { var_dump($manager, $product_id, $in_stock, $price, $product_attrs); exit; }; $parameters = [ 'product_id' => 1, 'name' => 'My beautiful sneaker', 'in_stock' => true, 'price' => 156.30, 'product_attrs' => [ 'size' => 12, 'color' => 'pink' ] ]; $arguments = (new ArgumentResolver([new ParameterResolver($parameters), new ContainerResolver($container)]))->resolve($acmeCallable); $acmeCallable(...$arguments);
创建自定义解析器
您可以创建自己的自定义解析器。在这个示例中,我们创建了一个基于 HTTP 请求会话的解析器。为了工作,解析器必须实现 Pollen\ArgumentResolver\ResolverInterface。
use Pollen\ArgumentResolver\ArgumentResolver; use Pollen\ArgumentResolver\ResolverInterface; class SessionResolver implements ResolverInterface { protected array $params; public function __construct() { $this->params = $_SESSION; } /** * @inheritDoc */ public function resolve(ReflectionParameter $parameter): ?array { $key = $parameter->getName(); if (!$value = $this->params[$key] ?? null) { return null; } if (!$this->matchType($parameter, $this->params[$key])) { return null; } return [$key, $value]; } /** * @param ReflectionParameter $parameter * @param mixed $value * * @return bool */ protected function matchType(ReflectionParameter $parameter, $value): bool { if (!$type = $parameter->getType()) { return true; } $typeName = $type->getName(); if ('array' === $typeName) { return is_array($value); } if ('callable' === $typeName) { return is_callable($value); } if (!$type->isBuiltin()) { if (!is_object($value)) { return false; } try { $class = new ReflectionClass($typeName); } catch (ReflectionException $e) { return false; } return $class->isInstance($value); } switch ($typeName) { case 'bool': return is_bool($value); case 'float': return is_float($value); case 'int': return is_int($value); case 'string': return is_string($value); case 'iterable': return is_iterable($value); } return true; } } $_SESSION['product_id'] = 1; $_SESSION['name'] = 'My beautiful sneaker'; $_SESSION['in_stock'] = true; $_SESSION['price'] = 156.30; $_SESSION['product_attrs'] = [ 'size' => 12, 'color' => 'pink', ]; $acmeCallable = static function (int $product_id, string $name, bool $in_stock, float $price, array $product_attrs) { var_dump($product_id, $in_stock, $price, $product_attrs); exit; }; $arguments = (new ArgumentResolver([new SessionResolver()]))->resolve($acmeCallable); $acmeCallable(...$arguments);
致谢
- 自由灵感来源于 Rybakit 在 ArgumentsResolver 的工作