在开发插件的时候,总是需要添加很多的其他类文件,如果library库太多导致在一个控制器引用很多个文件,导致忘记某个方法定义在什么类库,即便记得也需要写很多冗余代码
这时候Hook的作用就出来了,它可以将繁杂的代码量缩短到一行。
我们常规添加Hook方法如下
Hook::add($method, $namespace);
但是它只能针对单独一个方法进行添加,我们需要精确到告诉add对应的方法名和命名空间,
如果你有几十个方法或者几百个,那么就需要编写成百上千行
一招解决重复工作
首先在插件的appInit中,注册并添加你的自定义命名空间
Loader::addNamespace($space, ADDON_PATH. $addonName . DS . $directory);
然后遍历该命名空间下的类和公共方法,循环添加到我们的Hook事件当中
/**
* $addonsName 改为你的插件名
* $directory 改为你的命名空间目录
*/
public function appInit() {
Loader::addNamespace('behavior', ADDON_PATH. $addonsName . DS . $directory);
// 遍历命名空间里面的类名和方法
$listFile = $this->listDir(realpath(__DIR__). DS . $directory, "\\addons\\$addonsName\\$directory\\");
foreach($listFile as $item) {
foreach($item['method'] as $method) {
Hook::add($method, "\\addons\\$addonsName\\$directory\\".$item['className']);
}
}
}
/**
* @param $directory
* @return array|bool
* 读取扩展行为类库的所有类名和公共方法,子目录不参与计算
*/
private function listDir($directory, $namespace) {
$fileList = [];
if(is_dir($directory)) {
if($dir_handle = @opendir($directory)) {
while($filename = readdir($dir_handle)) {
if($filename != '.' && $filename != '..') {
$subFile = $directory. DS .$filename;
if(is_dir($subFile)) {
// return true;
} else {
$className = explode('.', $filename)[0];
$cls = $namespace.$className;
$ref = new \ReflectionClass(new $cls);
$methods = [];
foreach($ref->getMethods() as $item) {
if($item->isPublic()){
$methods[] = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $item->name));
}
}
array_push($fileList, [
'className' => $className,
'method' => $methods
]);
}
}
}
}
} else {
return false;
}
return $fileList;
}