marcojetson/php-decorators
Composer 安装命令:
composer require marcojetson/php-decorators
包简介
Python-like decorators for PHP
README 文档
README
Python-like decorators for PHP
Disclaimer
Please note that this is a proof of concept, use it at your own risk.
Usage
Specify decorators with the @Decorate annotation using one of the following formats:
- Class name::method name
- Class name (must implement __invoke)
- Function name
Decorators take the original method and the context as arguments and must return a function that takes the same arguments the original method does.
It's possible to add as many decorators as desired, always returning a valid callable for the next decorator.
(almost) Real life examples
In memory cache
class InMemoryCacheDecorator { private static $cache; public function __invoke($callable) { return function () use ($callable) { $args = func_get_args(); $key = serialize([$callable, $args]); if (!isset(static::$cache[$key])) { static::$cache[$key] = call_user_func_array($callable, $args); } return static::$cache[$key]; }; } } class MyClass { use Decorator\AnnotationDecoratorFactoryTrait; /** * @Decorate InMemoryCacheDecorator */ public function myMethod($name) { sleep(1); return 'Hello ' . $name; } } $x = MyClass::factory(); // or use new AnnotationDecorator(new MyClass()); echo $x->myMethod('Marco'), PHP_EOL; echo $x->myMethod('Marco'), ' (this time is cached)', PHP_EOL; echo $x->myMethod('Marco'), ' (this time is cached)', PHP_EOL; echo $x->myMethod('World'), PHP_EOL; echo $x->myMethod('World'), ' (this time is cached)', PHP_EOL; echo $x->myMethod('World'), ' (this time is cached)', PHP_EOL;
Cart promos
class Cart { private $total = 100; /** * @Decorate halfVat * @Decorate fixedDiscount */ public function calcTotal($vat) { return $this->total * (1 + $vat / 100); } } function halfVat($callable) { return function ($vat) use ($callable) { return $callable($vat / 2); }; } function fixedDiscount($callable) { return function ($vat) use ($callable) { $total = $callable($vat) - 5; return $total < 0 ? 0 : $total; }; } /** @var Cart $order */ $order = new Decorator\AnnotationDecorator(new Cart()); echo $order->calcTotal(21), PHP_EOL;
Controller requirements
function require_http_post($callable, $context) { return function () use ($callable, $context) { if ($context->getMethod() !== 'POST') { throw new \Exception('Not supported'); } return call_user_func_array($callable, func_get_args()); }; } class AddressController { use Decorator\AnnotationDecoratorFactoryTrait; private $method; public function __construct($method) { $this->method = $method; } public function getMethod() { return $this->method; } /** * @Decorate require_http_post */ public function deleteAction($id) { // delete... return 'success'; } } echo AddressController::factory('POST')->deleteAction(1), PHP_EOL; echo AddressController::factory('GET')->deleteAction(1), PHP_EOL;
Gotchas
- Only works for methods
- Not completely transparent, you need to use the factory method
- No parameters type hinting for the decorated class
统计信息
- 总下载量: 6
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 4
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: BSD-3-Clause
- 更新时间: 2015-06-18