裝飾器簡單解釋:把一個函式傳給裝飾器,並返回一個函式,替換掉原函式。
舉個 Python 的栗子:
import time
def time_recorder(fn):
def wrapper():
start = time.time()
fn()
print(time.time() - start)
return wrapper
@time_recorder
def test():
time.sleep(1)
print('test')
# 上面的裝飾器用法,相當於下面的語句
# test = time_recorder(test)
test()
輸出:
test
1.00072383881
在 Laravel 中,我們就在控制器中嘗試這個吧
首先,重寫控制器的 callAction
:
// 獲取註釋中的各種引數以及對應的值
// 反射居然不能直接獲取到各個引數,只能獲取到整個註釋的字串
// 直接 copy 一個:https://tomlankhorst.nl/get-phpdoc-parameters-of-a-method/
public function phpdocParams(\ReflectionMethod $method): array
{
// Retrieve the full PhpDoc comment block
$doc = $method->getDocComment();
if ($doc === false) {
return [];
}
// Trim each line from space and star chars
$lines = array_map(function ($line) {
return trim($line, " *");
}, explode("\n", $doc));
// Retain lines that start with an @
$lines = array_filter($lines, function ($line) {
return strpos($line, "@") === 0;
});
$args = [];
// Push each value in the corresponding @param array
foreach ($lines as $line) {
[$param, $value] = explode(' ', $line, 2);
$args[$param][] = $value;
}
return $args;
}
public function callAction($method, $parameters)
{
$methodReflection = new \ReflectionMethod(static::class, $method);
$decorators = $this->phpdocParams($methodReflection)['@decorator'] ?? [];
$decorators = array_reverse($decorators);
$fn = [$this, $method];
foreach ($decorators as $decorator) {
$fn = call_user_func($decorator, $fn);
}
return call_user_func_array($fn, $parameters);
}
定義兩個全域性輔助函式隨便試試:
function my_logger($fn)
{
return function () use ($fn) {
Log::info('start');
$res = $fn(...func_get_args());
Log::info('end');
// 這裡不搞個 return,會拿不到控制器的返回結果~~
return $res;
};
}
function time_recorder($fn)
{
return function () use ($fn) {
$start = microtime(true);
$res = $fn(...func_get_args());
Log::info('time spent: '.(microtime(true) - $start));
return $res;
};
}
在控制中使用裝飾器:
/**
* @param Request $request
*
* 這裡用了兩個裝飾器
* 包裹(裝飾)順序是從內(下)往外(上),執行順序是從外(上)往內(下)
*
* @decorator my_logger
* @decorator time_recorder
*
* @return mixed
*/
public function index(Request $request)
{
return response()->json($request->input());
}
瀏覽器訪問:xx.xx.xx/some-route?a=1&b=2
瀏覽器的結果:{"a":"1","b":"2"}
log 的結果:
[2020-04-07 08:50:47] local.INFO: start
[2020-04-07 08:50:47] local.INFO: time spent: 0.013785123825073
[2020-04-07 08:50:47] local.INFO: end
其實有點像中介軟體~~
本作品採用《CC 協議》,轉載必須註明作者和本文連結