核心代码
<?php
class Event {
private $callbacks = [];
private $holder;
public function __construct() {
$bt = debug_backtrace();
if (count($bt) < 2) {
$this->holder = null;
return;
}
$this->holder = &$bt[1]['object']; // 绑定创建者对象
}
// 注册回调:支持闭包、[对象, 方法名] 数组
public function attach() {
$args = func_get_args();
switch (count($args)) {
case 1:
if (is_callable($args[0])) {
$this->callbacks[] = $args[0];
}
break;
case 2:
if (is_object($args[0]) && is_string($args[1])) {
$this->callbacks[] = [$args[0], $args[1]];
}
break;
}
}
// 触发事件:仅允许 holder 对象调用
public function notify() {
$bt = debug_backtrace();
if ($this->holder && ((count($bt) >= 2 && $bt[count($bt)-1]['object'] !== $this->holder) || count($bt) < 2)) {
throw new Exception('Notify can only be called in holder');
}
$args = func_get_args();
foreach ($this->callbacks as $callback) {
call_user_func_array($callback, $args);
}
}
}
使用示例
class User {
public $onLogin;
public function __construct() {
$this->onLogin = new Event();
}
public function login($username) {
// 业务逻辑...
$this->onLogin->notify($username, time()); // 触发
}
}
$user = new User();
// 注册监听器
$user->onLogin->attach(function($name, $time) {
echo "用户 $name 于 $time 登录\n";
});
$user->onLogin->attach(new Logger(), 'logLogin'); // 对象方法
$user->login('张三'); // 输出: 用户 张三 于 1234567890 登录
设计亮点
- 创建者绑定:构造函数通过
debug_backtrace 获取实例化对象,notify 仅允许该对象调用,防止外部随意触发。
- 灵活回调:支持匿名函数、对象方法数组、静态方法字符串等所有
call_user_func_array 兼容形式。
- 轻量无依赖:纯 PHP 实现,无需扩展,适合中小项目。
注意事项
debug_backtrace 有性能开销,高频调用场景建议改用显式传递 $holder。
- PHP 7.1+ 推荐使用
Closure::fromCallable 统一回调格式。
- 大型项目可考虑 Symfony EventDispatcher、Laravel Events 等成熟组件。