首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實現輕量級事件監聽器:參考 jQuery 設計模式

     編輯:PHP 相關知識

核心功能

  • 支持單一事件綁定多個回調
  • 支持一次性事件(觸發後自動移除)
  • 支持事件移除(按索引或全部清空)
  • 支持任意參數透傳給回調
  • 兼容閉包、實例方法、靜態方法、函數名等多種可調用類型

核心類實現

<?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');

設計亮點解析

  1. 靜態屬性存儲:無需實例化,全局單例模式,調用簡潔。
  2. 一次性事件機制:在 trigger 遍歷時判斷 once 標誌,執行前先 remove,避免遍歷中修改數組導致索引錯亂。
  3. 參數透傳:利用 func_get_args() + call_user_func_array() 實現不定參數透傳。
  4. 兼容性:is_callable() 守衛確保所有 PHP 可調用類型均受支持。

擴展建議

  • 加入優先級參數,控制回調執行順序。
  • 引入命名空間隔離,避免事件名衝突。
  • 增加異步事件隊列,配合 Swoole/RoadRunner 實現非阻塞觸發。

這個輕量級事件系統僅 50 行核心代碼,卻涵蓋了觀察者模式的核心需求,非常適合中小型項目或作為大型框架事件組件的參考實現。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved