PHPのデコレータ

画像
私は、PHPでPythonスタイルのデコレータを実装するためのビジョンとベストプラクティスを共有することにしました。
ルアーとして、右の画像で使用する小さな例。 出力(デコレータ自体のロジックを実装した後):
ログ:b()を呼び出す
 int(42)

実装はC拡張の形式で行われ、PHP自体を再構築する必要はありません。 ただし、ダウンロードできないホスティングサイトでは開始されません。
現時点では、コードはベータ版です(必要な機能はすべて記述されていますが、おそらくバグとメモリリークがあります:))。 そのままです。 開発に協力したいという要望があれば、 githubでコミットを受け入れてうれしいです。


簡単な使用例:
<?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) */ 


デコレータは、常に関数を返す関数です。 外部関数は、最初のパラメーターとして代替関数を受け入れます。 pythonとは異なり、パラメーター付きのデコレーターは、関数を返す関数を返す関数としては記述されません...追加のパラメーターは、置き換えられた関数の後に単に渡されます。
 <?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) */ 


デコレータは組み合わせることができます:
 <?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})]" */ 


さらに、これらは逆の順序で実行されます。
@A
@B
@C
関数X

になります
A(B(C(X(...))))


パラメーターの数とそのタイプは任意であり、計算の怠lazさは一般に手を縛ります。
 <?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" */ 

さらに、デコレータの名前は、デコレータを記述するときではなく、呼び出し時に宣言された関数および静的メソッドである必要があります。 そして一般的に、あなたは実験することができます:
 <?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 ) */ 

まあ、誰もが自分のタスクのコンテキストでもっと面白いものを思いつくことができると確信しています。

技術的な問題


現時点では、デコレータを使用してコードを実行するときのサポートを確認しました:

たぶん他の何かが欠けています。

既知のバグ/機能から(機能について説明できます。バグはすぐに修正します):


PS調査で「非常に詳細が必要」という十分なオプションが選択された場合、この拡張機能のSishnaの実装の詳細な説明を含む投稿を書くことができます。

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


All Articles