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

CodeIgniter Hook 機制原理深度解析與擴充實戰

     編輯:PHP 綜合知識

Hook (鉤子) 是 CodeIgniter 提供的核心擴充機制,允許在框架執行關鍵節點 (預載入、控制器前/後、輸出前等) 注入自訂邏輯,而不修改核心檔案。本文深入剖析 system/core/Hooks.php 源碼、鉤子點時序、定義格式與實戰應用模式。

一、Hook 核心源碼邏輯 (簡化版)

class CI_Hooks {
    protected $enabled = FALSE;
    protected $hooks = [];      // 來自 config/hooks.php
    protected $in_progress = FALSE;

    public function __construct() {
        $this->_initialize();
    }

    protected function _initialize() {
        // 1. 讀取 config.php $config['enable_hooks']
        // 2. include(APPPATH . 'config/hooks.php') → $hook
        // 3. $this->hooks = $hook; $this->enabled = TRUE;
    }

    public function _call_hook($which) {
        if (!$this->enabled || empty($this->hooks[$which])) return;
        $hooks = $this->hooks[$which];
        // 支援單一陣列或多個陣列
        is_array(reset($hooks)) ? $this->_run_multiple($hooks) : $this->_run_hook($hooks);
    }

    protected function _run_hook($hook) {
        // $hook = ['class'=>'', 'function'=>'', 'filename'=>'', 'filepath'=>'', 'params'=>[]]
        $filepath = APPPATH . $hook['filepath'] . '/' . $hook['filename'];
        include_once $filepath;
        $obj = new $hook['class']();
        $obj->{$hook['function']}($hook['params']);
    }
}

二、七大標準鉤子點時序圖

1. pre_system          → 系統極早期,Benchmark/Config/Uri 尚未載入
2. pre_controller      → 路由完成、控制器類載入前
3. post_controller_constructor → 控制器 __construct() 執行後、方法執行前
4. post_controller     → 控制器方法執行完畢
5. display_override    → 覆寫 _display(),完全接管輸出
6. cache_override      → 覆寫 _display_cache(),自訂快取機制
7. post_system         → 最終輸出送出瀏覽器前

三、config/hooks.php 定義格式

$hook['pre_controller'] = [
    'class'    => 'AuthHook',
    'function' => 'check_login',
    'filename' => 'AuthHook.php',
    'filepath' => 'hooks',
    'params'   => ['redirect' => 'login']
];

// 同一掛載點多個 Hook (依陣列順序執行)
$hook['post_controller'] = [
    ['class' => 'LogHook', 'function' => 'write_access_log', 'filename' => 'LogHook.php', 'filepath' => 'hooks'],
    ['class' => 'ProfilerHook', 'function' => 'inject_profiler', 'filename' => 'ProfilerHook.php', 'filepath' => 'hooks'],
];

四、實戰範例:全域權限檢查 (pre_controller)

// application/hooks/AuthHook.php
class AuthHook {
    public function check_login($params = []) {
        $CI =& get_instance();
        $public = ['login', 'register', 'forgot_password'];
        $controller = $CI->router->fetch_class();
        $method = $CI->router->fetch_method();

        if (in_array($controller, $public) || in_array($method, $public)) return;

        if (!$CI->session->userdata('user_id')) {
            $redirect = $params['redirect'] ?? 'login';
            redirect($redirect);
        }
    }
}

五、進階應用模式

1. 多語言自動偵測 (pre_system)

class LanguageHook {
    public function detect() {
        $CI =& get_instance();
        $lang = $CI->input->cookie('lang') ?? substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
        $CI->config->set_item('language', in_array($lang, ['zh-tw','en']) ? $lang : 'zh-tw');
    }
}

2. API 回應統一格式化 (post_controller)

class ApiResponseHook {
    public function format() {
        $CI =& get_instance();
        if (strpos($CI->router->fetch_class(), 'Api_') === 0) {
            $data = $CI->output->get_output();
            $json = json_decode($data, TRUE);
            $CI->output->set_content_type('application/json')
                     ->set_output(json_encode([
                         'code' => 0,
                         'msg'  => 'success',
                         'data' => $json ?? $data
                     ]));
        }
    }
}

3. 條件式快取 (cache_override)

class CustomCacheHook {
    public function serve() {
        $CI =& get_instance();
        // 依使用者角色、Header 做差異化快取
        $cache_key = 'page_' . $CI->uri->uri_string() . '_' . $CI->session->userdata('role');
        if ($cached = $CI->cache->get($cache_key)) {
            $CI->output->set_output($cached);
            return TRUE; // 告知框架已處理
        }
        return FALSE; // 繼續正常流程
    }
}

六、注意事項與最佳實踐

  • 啟用順序: config.php → hooks.php → Hooks.php 初始化;修改 hooks.php 即時生效,無需重啟。
  • 避免在 Hook 執行重導向/輸出:pre_system 階段尚無 Output 類,直接 exit() 會跳過後續流程。
  • 取得 CI 實例: 必須用 $CI =& get_instance(); 而非 $this->ci (Hook 類非 CI 控制器)。
  • 效能影響: 每個請求都會載入 Hook 檔案;邏輯勿過重,必要時用 require_once 或自動載入。
  • 測試策略: 為每個 Hook 撰寫單元測試,模擬 $CI 注入依賴。

七、Hook vs Library vs Filter (CI4) 對照

特性CI3 HookCI3 LibraryCI4 Filter
執行時機固定 7 個點手動載入/自動載入Before/After 路由
耦合度低 (配置驅動)中 (需在 Controller 呼叫)低 (屬性標註)
適用場景橫切關注點 (日誌、權限、快取)業務邏輯封裝認證、CSRF、速率限制
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved