本文目录导读:

- WordPress风格的钩子系统
- 使用事件监听器(Event Listener)
- 中间件模式(Middleware Pattern)
- 使用属性(Attributes)注册(PHP 8+)
- 使用Composer事件(Composer Events)
- 最佳实践
PHP钩子(Hook)是一种设计模式,允许在特定事件发生时执行自定义代码,以下是几种常见的PHP钩子注册方式:
WordPress风格的钩子系统
class HookManager {
private static $filters = [];
private static $actions = [];
// 注册过滤器(修改数据)
public static function addFilter($hook, $callback, $priority = 10, $args = 1) {
self::$filters[$hook][$priority][] = [
'callback' => $callback,
'args' => $args
];
}
// 注册动作(执行操作)
public static function addAction($hook, $callback, $priority = 10, $args = 1) {
self::$actions[$hook][$priority][] = [
'callback' => $callback,
'args' => $args
];
}
// 执行过滤器
public static function applyFilters($hook, $value) {
if (!isset(self::$filters[$hook])) {
return $value;
}
$args = array_slice(func_get_args(), 2);
ksort(self::$filters[$hook]);
foreach (self::$filters[$hook] as $priority => $callbacks) {
foreach ($callbacks as $filter) {
$callback_args = array_merge(array($value), $args);
$value = call_user_func_array($filter['callback'],
array_slice($callback_args, 0, $filter['args']));
}
}
return $value;
}
// 执行动作
public static function doAction($hook, ...$args) {
if (!isset(self::$actions[$hook])) {
return;
}
ksort(self::$actions[$hook]);
foreach (self::$actions[$hook] as $priority => $callbacks) {
foreach ($callbacks as $action) {
call_user_func_array($action['callback'],
array_slice($args, 0, $action['args']));
}
}
}
}
// 注册钩子
HookManager::addFilter('text_content', function($text) {
return strtoupper($text);
}, 10, 1);
HookManager::addAction('user_login', function($username) {
// 记录日志
error_log("用户登录: $username");
}, 10, 1);
// 触发钩子
echo HookManager::applyFilters('text_content', 'hello world');
HookManager::doAction('user_login', 'JohnDoe');
使用事件监听器(Event Listener)
interface EventListenerInterface {
public function handle($event, $data);
}
class EventDispatcher {
private $listeners = [];
// 注册监听器
public function addListener($event, EventListenerInterface $listener, $priority = 0) {
$this->listeners[$event][$priority][] = $listener;
krsort($this->listeners[$event]);
}
// 触发事件
public function dispatch($event, $data = []) {
if (!isset($this->listeners[$event])) {
return;
}
foreach ($this->listeners[$event] as $listeners) {
foreach ($listeners as $listener) {
$listener->handle($event, $data);
}
}
}
}
class UserEventListener implements EventListenerInterface {
public function handle($event, $data) {
switch ($event) {
case 'user.created':
$this->sendWelcomeEmail($data['email']);
break;
case 'user.deleted':
$this->cleanupUserData($data['user_id']);
break;
}
}
}
$dispatcher = new EventDispatcher();
$dispatcher->addListener('user.created', new UserEventListener());
$dispatcher->dispatch('user.created', ['email' => 'test@example.com']);
中间件模式(Middleware Pattern)
class Middleware {
private $handlers = [];
// 注册中间件
public function use(callable $handler) {
$this->handlers[] = $handler;
}
public function handle($request, callable $finalHandler) {
$middleware = array_reverse($this->handlers);
$next = $finalHandler;
// 从最后一个中间件开始包装
foreach ($middleware as $handler) {
$next = function($req) use ($handler, $next) {
return $handler($req, $next);
};
}
return $next($request);
}
}
$app = new Middleware();
$app->use(function($request, $next) {
// 日志中间件
error_log("开始处理请求");
$response = $next($request);
error_log("请求处理完成");
return $response;
});
$app->use(function($request, $next) {
// 认证中间件
if (!$request['authenticated']) {
return "未授权访问";
}
return $next($request);
});
// 最终处理器
$response = $app->handle(['authenticated' => true], function($request) {
return "处理业务逻辑";
});
使用属性(Attributes)注册(PHP 8+)
#[Attribute]
class Hook {
public function __construct(
public string $name,
public int $priority = 10
) {}
}
class HooksCollector {
public static function registerFromClass(string $className) {
$reflection = new ReflectionClass($className);
$methods = $reflection->getMethods();
foreach ($methods as $method) {
$attributes = $method->getAttributes(Hook::class);
foreach ($attributes as $attribute) {
$hook = $attribute->newInstance();
HookManager::addAction(
$hook->name,
[$className, $method->getName()],
$hook->priority
);
}
}
}
}
class UserHooks {
#[Hook('user.created', 5)]
public static function onUserCreated($userId) {
error_log("用户已创建: $userId");
}
#[Hook('user.deleted')]
public static function onUserDeleted($userId) {
// 清理相关数据
}
}
// 自动注册所有钩子
HooksCollector::registerFromClass(UserHooks::class);
使用Composer事件(Composer Events)
利用Composer的autoload机制实现简单的钩子:
// hook.php 文件
return [
'hooks' => [
'before_render' => [
function($content) {
return str_replace(['<script>', '</script>'], '', $content);
},
function($content) {
return nl2br($content);
}
],
'after_save' => [
function($data) {
// 缓存清理
}
]
]
];
// 加载并使用
class HookLoader {
private $hooks;
public function __construct() {
$this->hooks = require 'hooks.php';
}
public function getHooks($name) {
return $this->hooks['hooks'][$name] ?? [];
}
}
最佳实践
- 命名约定:使用清晰的事件名称(如
user.login、order.created) - 优先级处理:支持优先级排序,让高级别优先执行
- 参数传递:明确传递参数数量和类型
- 错误处理:在钩子执行时捕获异常
- 文档记录:记录所有已注册的钩子及其用途
选择哪种方式取决于项目需求,简单项目用函数回调即可,大型框架建议使用完整的事件系统。