📜 ⬆️ ⬇️

PHP Decorators

image
I decided to share my vision and ideas on the implementation of the python-style decorators in PHP.
As zavlekalochki a small example of the use of the image on the right. Displays (after the implementation of the logic of the decorators themselves):
 Log: calling b ()
 int (42)

The implementation is implemented as a C extension and does not require rebuilding PHP itself. But it will not start on hosting, where you can not download your so'shku.
At the moment, the code is in beta (all the necessary functionality is written, but there are probably bugs and memory leaks :)). So as is. Well, if you want to help in development, I will be glad to accept commits on github .


A simple example of use:
<?php function double($func) { return function() use($func) { return 2*call_user_func_array($func, func_get_args()); }; } @double function a() { return 21; } var_dump(a()); /* : int(42) */ 


Decorators are always functions that return functions. The external function takes the first parameter to replace the function. Unlike python, the decorator with parameters is not described as a function that returns a function that returns a function ... Additional parameters are simply passed after the function being replaced:
 <?php function add($func, $v=0) { return function() use($func, $v) { return $v+call_user_func_array($func, func_get_args()); }; } @add(1) function a() { return 1; } var_dump(a()); /* : int(2) */ 

')
Decorators can be combined:
 <?php function dec($func, $p='[]') { return function() use($func, $p) { $s = call_user_func_array($func, func_get_args()); return $p[0].$s.$p[1]; }; } @dec function a() { return 'I'; } var_dump(a()); @dec('{}') function b() { return 'am'; } var_dump(b()); @dec @dec('()') @dec('{}') function c() { return 'here'; } var_dump(c()); /* : string(3) "[I]" string(4) "{am}" string(10) "[({here})]" */ 


In this case, they are performed in the opposite order:
@A
@B
@C
function X

turns into
A (B (C (X (...))))


The number of parameters and their types are arbitrary, and the laziness of the calculations is generally a free hand:
 <?php class Logger { const INFO = 'INFO'; public static function log($func, $text='', $level=self::INFO, $prefix='') { return function() use($func, $text, $level, $prefix) { printf("%s%s: %s\n", $prefix, $level, $text); return call_user_func_array($func, func_get_args()); }; } } @Logger::log('calling a()', Logger::INFO, date('Ymd H:i:s').': ') function a() { return 'Hello'; } var_dump(a()); /* : 2013-05-24 14:22:23: INFO: calling a() string(5) "Hello" */ 

The names of decorators should be functions and static methods, moreover, declared at the time of the call, and not in the description of the decorator. Anyway, you can experiment:
 <?php class Arr { public static function map($func, $cb) { return function() use($func, $cb) { $v = call_user_func_array($func, func_get_args()); return array_map($cb, $v); }; } } class Foo { /*      */ @Arr::map(function($i){return -$i;}) /** *        *     * * @return array */ public function bar() { return range(1, 3); } } $foo = new Foo(); print_r($foo->bar()); /* : Array ( [0] => -1 [1] => -2 [2] => -3 ) */ 

Well, I'm sure everyone here can come up with something more interesting in the context of their tasks.

Technical issues


At the moment I checked the support when executing the code with the decorators through:

Perhaps something else is missing.

From known bugs / features (features can be discussed; I will fix bugs soon):


PS If the survey picks up enough options "Looking for great details", I can write a post with a detailed description of the Sishna implementation of this extension.

Source: https://habr.com/ru/post/180827/


All Articles