<?php
class Event
{
protected static $listens = [];
/**
* 綁定事件
* @param string $event 事件名
* @param callable $callback 回調
* @param bool $once 是否一次性
* @return bool
*/
public static function listen($event, $callback, $once = false)
{
if (!is_callable($callback)) {
return false;
}
self::$listens[$event][] = ['callback' => $callback, 'once' => $once];
return true;
}
/** 綁定一次性事件 */
public static function one($event, $callback)
{
return self::listen($event, $callback, true);
}
/**
* 移除事件
* @param string $event
* @param int|null $index 為 null 移除該事件所有監聽
*/
public static function remove($event, $index = null)
{
if (is_null($index)) {
unset(self::$listens[$event]);
} else {
unset(self::$listens[$event][$index]);
}
}
/** 觸發事件 */
public static function trigger()
{
if (!func_num_args()) {
return;
}
$args = func_get_args();
$event = array_shift($args);
if (!isset(self::$listens[$event])) {
return false;
}
foreach ((array) self::$listens[$event] as $index => $listen) {
$callback = $listen['callback'];
// 一次性事件:執行前先移除
if ($listen['once']) {
self::remove($event, $index);
}
call_user_func_array($callback, $args);
}
}
}
<?php
// 綁定普通事件
Event::listen('walk', function () {
echo "I am walking...\n";
});
// 綁定一次性事件
Event::listen('walk', function () {
echo "I am listening...\n";
}, true);
// 第一次觸發:兩個回調都執行
Event::trigger('walk');
/* 輸出:
I am walking...
I am listening...
*/
// 第二次觸發:一次性事件已移除,僅剩普通事件
Event::trigger('walk');
/* 輸出:
I am walking...
*/
<?php
Event::one('say', function ($name = '') {
echo "I am {$name}\n";
});
Event::trigger('say', 'deeka'); // 輸出 I am deeka
Event::trigger('say', 'deeka'); // 不再執行(一次性事件已移除)
<?php
class Foo
{
public function bar()
{
echo "Foo::bar() is called\n";
}
public function test()
{
echo "Foo::test() is called, args: " . json_encode(func_get_args()) . "\n";
}
}
$foo = new Foo;
// 實例方法
Event::listen('bar', [$foo, 'bar']);
Event::trigger('bar');
// 實例方法帶參數
Event::listen('test', [$foo, 'test']);
Event::trigger('test', 1, 2, 3);
<?php
class Bar
{
public static function foo()
{
echo "Bar::foo() is called\n";
}
}
// 靜態方法:數組寫法
Event::listen('bar1', ['Bar', 'foo']);
Event::trigger('bar1');
// 靜態方法:字符串寫法
Event::listen('bar2', 'Bar::foo');
Event::trigger('bar2');
// 普通函數
function bar()
{
echo "bar() is called\n";
}
Event::listen('bar3', 'bar');
Event::trigger('bar3');
trigger 遍歷時判斷 once 標誌,執行前先 remove,避免遍歷中修改數組導致索引錯亂。func_get_args() + call_user_func_array() 實現不定參數透傳。is_callable() 守衛確保所有 PHP 可調用類型均受支持。這個輕量級事件系統僅 50 行核心代碼,卻涵蓋了觀察者模式的核心需求,非常適合中小型項目或作為大型框架事件組件的參考實現。