Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

perf: filter discovery tokenizes the app and system `Config/Filters.php` on every request

未關閉 適合新手
#10,616 1 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
2/5
預估耗時
1-3 小時
新手友好度
72/100
Issue 類型
重構
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
php

研究方向

從私有方法 discoverFilters() 開始,它由 Filters 建構函式呼叫。查看 FileLocator::search() 的結果如何傳遞給 getClassname()。在該呼叫之前新增一項檢查,略過 APPPATH 和 SYSTEMPATH 下的 Config/Filters.php 路徑,其他路徑保持不變。執行 tests/system/Filters/FiltersTest.php。完成的標準是:透過 Services::injectMock('locator', ...) 注入的 spy locator 不再對應用或系統檔案產生 getClassname() 呼叫,同時 tests/_support 中的自訂過濾器及其別名 test-customfilter 仍能正常運作。

由索引模型根據 Issue 內容生成。

描述

Problem

Filters::__construct() calls the deprecated discoverFilters() on every request when filter discovery is on, which it is by default. That method finds every Config/Filters.php across all namespaces. For each file, it calls FileLocator::getClassname(), which runs file_get_contents() and token_get_all() on the file.

In a default app, discovery finds only two files:

  • app/Config/Filters.php
  • system/Config/Filters.php

Both get read and tokenized, and then both are skipped, because their class is Config\Filters or CodeIgniter\Config\Filters. So every request pays to parse two files it never uses.

Measurements

PHP 8.3 on macOS, OPcache on, production mode, warm. Each number is averaged over 300 runs.

Case Time
new Filters(...), discovery on (default) ~103 µs
new Filters(...), discovery off ~0.2 µs
FileLocator::search('Config/Filters.php') ~15 µs
FileLocator::getClassname() per file ~42 µs

For a full request to a bare closure route, Services::filters() is about 126 µs. That's the largest single cost left once #10615 lands, at about 14–18% of the request.

Proposal

In discoverFilters(), compare each found path against APPPATH . 'Config/Filters.php' and SYSTEMPATH . 'Config/Filters.php' before calling getClassname(). Skip those two paths with no file read.

  • FileLocator::search() already returns real paths, and APPPATH and SYSTEMPATH are real paths too, so a plain string compare works.
  • Every other file keeps today's class-name check, unchanged. Module and package discovery files are still included as they are now.

With the default setup, the cost drops to the search() call alone, about 15 µs.

Compatibility

  • No public or protected API changes. discoverFilters() is private.
  • There's one edge case. Today, if app/Config/Filters.php declared some class other than Config\Filters, discovery would include it. After this change, that file is skipped. This layout breaks the framework's own conventions, and filter discovery has been deprecated since 4.4.2. So no changelog or upgrade-guide entry is planned.

Tests

Add a regression test in tests/system/Filters/FiltersTest.php. It uses a spy FileLocator, injected with Services::injectMock('locator', ...), that records the paths passed to getClassname(). The test asserts that:

  • getClassname() is never called for the app or system Config/Filters.php.
  • getClassname() is still called for tests/_support/Config/Filters.php, and the test-customfilter alias it adds is still registered.

The existing discovery test (FiltersTest.php:488) keeps covering the third-party path.

Related

  • #10615. It covers config construction cost. This issue is independent and can land separately.
主要語言
PHP
星號
6k
分支
2k
平均合併
1 天 22 小時
30 天內合併 PR
59

環境準備

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

codeigniter4/CodeIgniter4 的其他 Issue

查看 codeigniter4/CodeIgniter4 的全部 Issue

相似的 Issue

更多 PHP Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。