marcojetson / php-decorators
PHP的Python-like装饰器
dev-master
2015-06-18 21:33 UTC
Requires
- php: >=5.4
- phpdocumentor/reflection-docblock: 2.0.*
Requires (Dev)
- codeclimate/php-test-reporter: ^0.1.2
- phpunit/phpunit: 4.6.*
This package is not auto-updated.
Last update: 2024-09-14 17:42:54 UTC
README
PHP的Python-like装饰器
免责声明
请注意,这是一个概念验证,请在自己的风险下使用。
用法
使用以下格式之一通过@Decorate
注解指定装饰器
- 类名::方法名
- 类名(必须实现__invoke)
- 函数名
装饰器接受原始方法和上下文作为参数,并必须返回一个接受与原始方法相同参数的函数。
可以添加任意数量的装饰器,始终为下一个装饰器返回有效的可调用对象。
(几乎)真实示例
内存缓存
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;
购物车促销
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;
控制器要求
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;
注意事项
- 仅适用于方法
- 不完全透明,需要使用工厂方法
- 装饰的类没有参数类型提示