From d8fe78449cbd76d0d54560efaefd10c98f1235a4 Mon Sep 17 00:00:00 2001 From: n0nag0n Date: Mon, 10 Aug 2026 23:29:08 -0600 Subject: [PATCH 01/25] Fix flight.allow_method_override not disabling method override (GHSA-vr9m-jx6f-hhj6) Assign Request::$allowMethodOverride on the class before any Request is built, so the constructor does not cache an overridden verb while the static still defaults to true. When override is disabled and an override header or _method field is present, recompute the cached request method so early Flight::request() access cannot keep a spoofed DELETE/PUT/PATCH. Add regression tests for the Engine start path, early request construction, _method, and intentional manual method assignment without override input. --- flight/Engine.php | 20 ++++- tests/EngineTest.php | 173 ++++++++++++++++++++++++++++++++++++++++++ tests/RequestTest.php | 47 ++++++++++++ 3 files changed, 238 insertions(+), 2 deletions(-) diff --git a/flight/Engine.php b/flight/Engine.php index db00d5b..880decf 100644 --- a/flight/Engine.php +++ b/flight/Engine.php @@ -227,8 +227,24 @@ class Engine // which causes a lot of problems. This will be removed // in v4 $self->response()->v2_output_buffering = $this->get('flight.v2.output_buffering'); - // Propagate method override setting to Request - $self->request()::$allowMethodOverride = (bool) $self->get('flight.allow_method_override'); + + // Propagate method override setting to Request. + // Assign the static on the class first — do not call request() before this, + // or Request's constructor caches the method while the flag is still the default (true). + Request::$allowMethodOverride = (bool) $self->get('flight.allow_method_override'); + + // If a Request was already built earlier (common: apps touch request() before start) + // while override was still enabled, refresh the cached verb when override is off + // and an override input is present. When no override input exists, leave any + // intentional manual method assignment alone. + if (Request::$allowMethodOverride === false) { + $hasOverrideInput = Request::getVar('HTTP_X_HTTP_METHOD_OVERRIDE') !== '' + || isset($_REQUEST['_method']); + if ($hasOverrideInput === true) { + $request = $self->request(); + $request->method = Request::getMethod(); + } + } }); $this->initialized = true; diff --git a/tests/EngineTest.php b/tests/EngineTest.php index e2d8471..7c8226e 100644 --- a/tests/EngineTest.php +++ b/tests/EngineTest.php @@ -23,11 +23,18 @@ class EngineTest extends TestCase public function setUp(): void { $_SERVER = []; + $_REQUEST = []; + $_GET = []; + $_POST = []; + // Static flag leaks across tests (and across Engine instances). + Request::$allowMethodOverride = true; } public function tearDown(): void { $_SERVER = []; + $_REQUEST = []; + Request::$allowMethodOverride = true; } public function testInitBeforeStart(): void @@ -1207,4 +1214,170 @@ class EngineTest extends TestCase $this->expectExceptionMessage("/path/to/nowhere cannot be found."); $engine->download('/path/to/nowhere'); } + + /** + * Regression for GHSA method-override opt-out: setting the flag to false must + * prevent X-HTTP-Method-Override from selecting a different route. + * + * The original mitigation assigned Request::$allowMethodOverride via + * $self->request()::$allowMethodOverride, which built Request (and cached the + * overridden verb) before the static was set. + */ + public function testAllowMethodOverrideFalseBlocksHeaderOverrideOnStart(): void + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['REQUEST_URI'] = '/test'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE'; + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + $_SERVER['SERVER_NAME'] = 'localhost'; + $_SERVER['HTTP_HOST'] = 'localhost'; + + $engine = new Engine(); + $engine->set('flight.allow_method_override', false); + + $hit = null; + $engine->route('GET /test', function () use (&$hit) { + $hit = 'get'; + echo 'get'; + }); + $engine->route('DELETE /test', function () use (&$hit) { + $hit = 'delete'; + echo 'delete'; + }); + + $this->expectOutputString('get'); + $engine->start(); + + $this->assertSame('get', $hit); + $this->assertFalse(Request::$allowMethodOverride); + $this->assertSame('GET', $engine->request()->method); + } + + public function testAllowMethodOverrideFalseBlocksPostMethodFieldOnStart(): void + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_SERVER['REQUEST_URI'] = '/test'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + $_SERVER['SERVER_NAME'] = 'localhost'; + $_SERVER['HTTP_HOST'] = 'localhost'; + $_REQUEST['_method'] = 'PUT'; + + $engine = new Engine(); + $engine->set('flight.allow_method_override', false); + + $hit = null; + $engine->route('POST /test', function () use (&$hit) { + $hit = 'post'; + echo 'post'; + }); + $engine->route('PUT /test', function () use (&$hit) { + $hit = 'put'; + echo 'put'; + }); + + $this->expectOutputString('post'); + $engine->start(); + + $this->assertSame('post', $hit); + $this->assertSame('POST', $engine->request()->method); + } + + public function testAllowMethodOverrideTrueStillHonorsHeaderOnStart(): void + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['REQUEST_URI'] = '/test'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE'; + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + $_SERVER['SERVER_NAME'] = 'localhost'; + $_SERVER['HTTP_HOST'] = 'localhost'; + + $engine = new Engine(); + // default is true; set explicitly for clarity + $engine->set('flight.allow_method_override', true); + + $hit = null; + $engine->route('GET /test', function () use (&$hit) { + $hit = 'get'; + echo 'get'; + }); + $engine->route('DELETE /test', function () use (&$hit) { + $hit = 'delete'; + echo 'delete'; + }); + + $this->expectOutputString('delete'); + $engine->start(); + + $this->assertSame('delete', $hit); + $this->assertTrue(Request::$allowMethodOverride); + $this->assertSame('DELETE', $engine->request()->method); + } + + /** + * App code often touches request() before start() (set url, inspect headers, etc.). + * The flag must still win even when Request was constructed early under the default. + */ + public function testAllowMethodOverrideFalseRefreshesMethodIfRequestBuiltEarly(): void + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['REQUEST_URI'] = '/test'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE'; + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + $_SERVER['SERVER_NAME'] = 'localhost'; + $_SERVER['HTTP_HOST'] = 'localhost'; + + $engine = new Engine(); + $engine->set('flight.allow_method_override', false); + + // Construct Request while static is still the default (true) + $this->assertTrue(Request::$allowMethodOverride); + $early = $engine->request(); + $this->assertSame('DELETE', $early->method, 'pre-start construction still sees default override=on'); + + $hit = null; + $engine->route('GET /test', function () use (&$hit) { + $hit = 'get'; + echo 'get'; + }); + $engine->route('DELETE /test', function () use (&$hit) { + $hit = 'delete'; + echo 'delete'; + }); + + $this->expectOutputString('get'); + $engine->start(); + + $this->assertSame('get', $hit); + $this->assertFalse(Request::$allowMethodOverride); + $this->assertSame('GET', $engine->request()->method); + $this->assertSame($early, $engine->request(), 'same Request instance is refreshed, not replaced'); + } + + public function testAllowMethodOverrideFalseDoesNotClobberManualMethodWithoutOverrideInput(): void + { + // No X-HTTP-Method-Override / _method — manual method assignment must survive start(). + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['REQUEST_URI'] = '/someRoute'; + $_SERVER['SCRIPT_NAME'] = '/index.php'; + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; + $_SERVER['SERVER_NAME'] = 'localhost'; + $_SERVER['HTTP_HOST'] = 'localhost'; + + $engine = new Engine(); + $engine->set('flight.allow_method_override', false); + $engine->route('GET /someRoute', function () { + echo 'i ran'; + }, true); + $engine->request()->method = 'HEAD'; + $engine->request()->url = '/someRoute'; + + $this->expectOutputString(''); + $engine->start(); + + $this->assertSame('HEAD', $engine->request()->method); + } } diff --git a/tests/RequestTest.php b/tests/RequestTest.php index acc6e18..7954228 100644 --- a/tests/RequestTest.php +++ b/tests/RequestTest.php @@ -31,11 +31,15 @@ class RequestTest extends TestCase $_COOKIE = []; $_FILES = []; + // Static flag leaks across tests; always restore the framework default. + Request::$allowMethodOverride = true; + $this->request = new Request(); } protected function tearDown(): void { + Request::$allowMethodOverride = true; unset($_REQUEST); unset($_SERVER); } @@ -127,6 +131,49 @@ class RequestTest extends TestCase $this->assertEquals('PUT', $request->method); } + public function testMethodOverrideDisabledIgnoresHeader(): void + { + Request::$allowMethodOverride = false; + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE'; + + $request = new Request(); + + $this->assertSame('GET', $request->method); + $this->assertSame('GET', Request::getMethod()); + } + + public function testMethodOverrideDisabledIgnoresPostField(): void + { + Request::$allowMethodOverride = false; + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_REQUEST['_method'] = 'PUT'; + + $request = new Request(); + + $this->assertSame('POST', $request->method); + $this->assertSame('POST', Request::getMethod()); + } + + public function testMethodOverrideFlagMustBeSetBeforeConstruction(): void + { + // Documents the caching behavior: flipping the static after construct + // does not rewrite the already-cached $request->method. + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'DELETE'; + + Request::$allowMethodOverride = true; + $request = new Request(); + $this->assertSame('DELETE', $request->method); + + Request::$allowMethodOverride = false; + $this->assertSame('DELETE', $request->method, 'cached method is not auto-refreshed'); + $this->assertSame('GET', Request::getMethod(), 'getMethod() respects the new flag'); + + $request->method = Request::getMethod(); + $this->assertSame('GET', $request->method); + } + public function testHttps(): void { $_SERVER['HTTPS'] = 'on'; From dc48746b3f8fc6d139e411810b3807dcd514adf1 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Thu, 13 Aug 2026 23:46:24 -0400 Subject: [PATCH 02/25] update code format instructions to PSR12 in documentation --- .gemini/GEMINI.md | 4 ++-- .github/copilot-instructions.md | 4 ++-- AGENTS.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md index 226a40d..9a45b54 100644 --- a/.gemini/GEMINI.md +++ b/.gemini/GEMINI.md @@ -16,11 +16,11 @@ This is the main FlightPHP core library for building fast, simple, and extensibl - Run tests: `composer test` (uses phpunit/phpunit and spatie/phpunit-watcher) - Run test server: `composer test-server` or `composer test-server-v2` - Lint code & Check code style: `composer lint` (uses phpstan/phpstan, level 6) -- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR1) +- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR12) - Test coverage: `composer test-coverage` ## Coding Standards -- Follow PSR1 coding standards (enforced by PHPCS) +- Follow PSR12 coding standards (enforced by PHPCS) - Use strict comparisons (`===`, `!==`) - PHPStan level 6 compliance - Focus on PHP 7.4 compatibility (avoid PHP 8+ only features) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 226a40d..9a45b54 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -16,11 +16,11 @@ This is the main FlightPHP core library for building fast, simple, and extensibl - Run tests: `composer test` (uses phpunit/phpunit and spatie/phpunit-watcher) - Run test server: `composer test-server` or `composer test-server-v2` - Lint code & Check code style: `composer lint` (uses phpstan/phpstan, level 6) -- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR1) +- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR12) - Test coverage: `composer test-coverage` ## Coding Standards -- Follow PSR1 coding standards (enforced by PHPCS) +- Follow PSR12 coding standards (enforced by PHPCS) - Use strict comparisons (`===`, `!==`) - PHPStan level 6 compliance - Focus on PHP 7.4 compatibility (avoid PHP 8+ only features) diff --git a/AGENTS.md b/AGENTS.md index 226a40d..9a45b54 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -16,11 +16,11 @@ This is the main FlightPHP core library for building fast, simple, and extensibl - Run tests: `composer test` (uses phpunit/phpunit and spatie/phpunit-watcher) - Run test server: `composer test-server` or `composer test-server-v2` - Lint code & Check code style: `composer lint` (uses phpstan/phpstan, level 6) -- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR1) +- Beautify code: `composer format` (uses squizlabs/php_codesniffer, PSR12) - Test coverage: `composer test-coverage` ## Coding Standards -- Follow PSR1 coding standards (enforced by PHPCS) +- Follow PSR12 coding standards (enforced by PHPCS) - Use strict comparisons (`===`, `!==`) - PHPStan level 6 compliance - Focus on PHP 7.4 compatibility (avoid PHP 8+ only features) From dddd6ab72a7e6779a07533b17f1962c624746f8f Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Thu, 13 Aug 2026 23:55:15 -0400 Subject: [PATCH 03/25] update the coding standards to PSR12 --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4b1af6d..3f60042 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two * **Dependencies** - We strive to be dependency free in Flight. Yes even polyfills, yes even `Interface` only repos like `psr/container`. The fewer dependencies, the fewer your exposed attack vectors. -* **Coding Standards** - We use PSR1 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are: +* **Coding Standards** - We use PSR12 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are: * PHPStan is at level 6. * `===` instead of truthy or falsey statements like `==` or `!is_array()`. From 412faa120f62d01b36628eed5e6171abc0c55b10 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Thu, 13 Aug 2026 23:55:44 -0400 Subject: [PATCH 04/25] adjust the php versions in the tests --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f60042..e6acc53 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two * **Core functionality vs Plugin** - Have a conversation with us in the [chatroom](https://matrix.to/#/!cTfwPXhpkTXPXwVmxY:matrix.org?via=matrix.org&via=leitstelle511.net&via=integrations.ems.host) to know if your idea is worth makes sense in the framework or in a plugin. -* **Testing** - Until automated testing is put into place, any PRs must pass unit testing in PHP 7.4 and PHP 8.2+. Additionally you need to run `composer test-server` and `composer test-server-v2` and ensure all the header links work correctly. +* **Testing** - Until automated testing is put into place, any PRs must pass unit testing in PHP 7.4 to PHP 8.5+. Additionally you need to run `composer test-server` and `composer test-server-v2` and ensure all the header links work correctly. #### **Did you find a bug?** From fa08cd68ff564997bdc030aefde90a610acae76e Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Thu, 13 Aug 2026 23:56:38 -0400 Subject: [PATCH 05/25] remove restriction about the ! (NOT) operator --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6acc53..3bf7cbc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two * **Coding Standards** - We use PSR12 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are: * PHPStan is at level 6. - * `===` instead of truthy or falsey statements like `==` or `!is_array()`. + * `===` instead of truthy or falsey statements like `==`. * **PHP 7.4 Focused** - We do not make PHP 8+ focused enhancements on the framework as the focus is maintaining PHP 7.4. From a86e4078ca247fe6234bbb0264770f32ecae71a0 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Thu, 13 Aug 2026 23:57:20 -0400 Subject: [PATCH 06/25] improve the redaction of CONTRIBUTING.md about security vulnerabilities --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3bf7cbc..6152b09 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two * **Coding Standards** - We use PSR12 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are: * PHPStan is at level 6. * `===` instead of truthy or falsey statements like `==`. - + * **PHP 7.4 Focused** - We do not make PHP 8+ focused enhancements on the framework as the focus is maintaining PHP 7.4. * **Core functionality vs Plugin** - Have a conversation with us in the [chatroom](https://matrix.to/#/!cTfwPXhpkTXPXwVmxY:matrix.org?via=matrix.org&via=leitstelle511.net&via=integrations.ems.host) to know if your idea is worth makes sense in the framework or in a plugin. @@ -21,7 +21,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two #### **Did you find a bug?** -* **Do not open up a GitHub issue if the bug is a security vulnerability**. Instead contact maintainers directly via email to safely pass in the information related to the security vuln. +* **Do not open up a GitHub issue if the bug is a security vulnerability**. Instead contact maintainers directly via email to safely pass in the information related to the security vulnerability. * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/flightphp/core/issues). From b28716c3efbfa640a72a7b64a9d0df91ed562ee1 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Fri, 14 Aug 2026 00:08:18 -0400 Subject: [PATCH 07/25] improve format and clarity in README.md --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9a043f7..c9a2042 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,10 @@ composer require flightphp/core or you can download a zip of this repo. Then you would have a basic `index.php` file like the following: ```php -// if installed with composer -require 'vendor/autoload.php'; -// or if installed manually by zip file -// require 'flight/Flight.php'; +require 'flight/autoload.php'; Flight::route('/', function () { - echo 'hello world!'; + echo 'hello world!'; }); Flight::start(); @@ -38,17 +35,17 @@ Flight::start(); Yes! Flight is fast. It is one of the fastest PHP frameworks available. You can see all the benchmarks at [TechEmpower](https://www.techempower.com/benchmarks/#section=data-r18&hw=ph&test=frameworks) -See the benchmark below with some other popular PHP frameworks. This is measured in requests processed within the same timeframe. +See the benchmark below with some other popular PHP frameworks. This is measured in requests processed within the same timeframe. | Framework | Plaintext Requests| JSON Requests| | --------- | ------------ | ------------ | | Flight | 190,421 | 182,491 | | Yii | 145,749 | 131,434 | -| Fat-Free | 139,238 | 133,952 | +| Fat-Free | 139,238 | 133,952 | | Slim | 89,588 | 87,348 | | Phalcon | 95,911 | 87,675 | | Symfony | 65,053 | 63,237 | -| Lumen | 40,572 | 39,700 | +| Lumen | 40,572 | 39,700 | | Laravel | 26,657 | 26,901 | | CodeIgniter | 20,628 | 19,901 | @@ -75,9 +72,10 @@ If you have a current project on v2, you should be able to upgrade to v3 with no > [!IMPORTANT] > Flight requires `PHP 7.4` or greater. -**Note:** PHP 7.4 is supported because at the current time of writing (2024) PHP 7.4 is the default version for some LTS Linux distributions. Forcing a move to PHP >8 would cause a lot of heartburn for those users. - -The framework also supports PHP >8. +> [!NOTE] +> PHP 7.4 is supported because at the current time of writing (2024) PHP 7.4 is the default version for some LTS Linux distributions. +> Forcing a move to PHP 8 would cause a lot of heartburn for those users. +> The framework also supports PHP 8. # Roadmap From b464dc18f40299c8d47541966738fddde39ebc27 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Fri, 14 Aug 2026 00:58:03 -0400 Subject: [PATCH 08/25] PSR12 -> PSR-12 Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6152b09..d6d9f65 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two * **Dependencies** - We strive to be dependency free in Flight. Yes even polyfills, yes even `Interface` only repos like `psr/container`. The fewer dependencies, the fewer your exposed attack vectors. -* **Coding Standards** - We use PSR12 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are: +* **Coding Standards** - We use PSR-12 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are: * PHPStan is at level 6. * `===` instead of truthy or falsey statements like `==`. From ae0440eb8000e8d8a407270b20e1431a20f8fd50 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Fri, 14 Aug 2026 01:00:01 -0400 Subject: [PATCH 09/25] remove "Until automated testing is put into place" CI Tests were implemented and running successfully Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6d9f65..956c789 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two * **Core functionality vs Plugin** - Have a conversation with us in the [chatroom](https://matrix.to/#/!cTfwPXhpkTXPXwVmxY:matrix.org?via=matrix.org&via=leitstelle511.net&via=integrations.ems.host) to know if your idea is worth makes sense in the framework or in a plugin. -* **Testing** - Until automated testing is put into place, any PRs must pass unit testing in PHP 7.4 to PHP 8.5+. Additionally you need to run `composer test-server` and `composer test-server-v2` and ensure all the header links work correctly. +* **Testing** - PRs must pass unit tests on PHP 7.4 through PHP 8.5+. Additionally you need to run `composer test-server` and `composer test-server-v2` and ensure all the header links work correctly. #### **Did you find a bug?** From d566684b7e1ff9353848eeb635db38d4e3fd57d4 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Fri, 14 Aug 2026 01:01:22 -0400 Subject: [PATCH 10/25] improve redaction about reporting security vulnerabilities Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 956c789..99b106c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two #### **Did you find a bug?** -* **Do not open up a GitHub issue if the bug is a security vulnerability**. Instead contact maintainers directly via email to safely pass in the information related to the security vulnerability. +* **Do not open up a GitHub issue if the bug is a security vulnerability**. Instead contact maintainers directly via email to safely share details about the security vulnerability. * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/flightphp/core/issues). From cc0116928167a7accc9948eff4a660caeaeb13f9 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Fri, 14 Aug 2026 01:01:46 -0400 Subject: [PATCH 11/25] falsey -> falsy Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 99b106c..1004dd2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ Flight aims to be simple and fast. Anything that compromises either of those two * **Coding Standards** - We use PSR-12 coding standards enforced by PHPCS. Some standards that either need additional configuration or need to be manually done are: * PHPStan is at level 6. - * `===` instead of truthy or falsey statements like `==`. + * `===` instead of truthy or falsy statements like `==`. * **PHP 7.4 Focused** - We do not make PHP 8+ focused enhancements on the framework as the focus is maintaining PHP 7.4. From cff442d96470684ed139dbaafceb4c01a45a0823 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Fri, 14 Aug 2026 01:57:43 -0400 Subject: [PATCH 12/25] normalize and simplify @copyright and @license phpdoc tags based on phpDocumentor recommendations to clean symbols hovers --- flight/core/Dispatcher.php | 4 ++-- flight/core/Loader.php | 4 ++-- flight/net/Request.php | 4 ++-- flight/net/Response.php | 4 ++-- flight/net/Route.php | 4 ++-- flight/net/Router.php | 4 ++-- flight/template/View.php | 4 ++-- flight/util/Collection.php | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/flight/core/Dispatcher.php b/flight/core/Dispatcher.php index 62ff7f9..f0f5b2a 100644 --- a/flight/core/Dispatcher.php +++ b/flight/core/Dispatcher.php @@ -18,8 +18,8 @@ use TypeError; * allows you to hook other functions to an event that can modify the * input parameters and/or the output. * - * @license MIT, http://flightphp.com/license - * @copyright Copyright (c) 2011, Mike Cao + * @copyright 2011 [Mike Cao](https://mikecao.com) + * @license https://docs.flightphp.com/license MIT * @phpstan-template EngineTemplate of object */ class Dispatcher diff --git a/flight/core/Loader.php b/flight/core/Loader.php index 92deceb..63bafd9 100644 --- a/flight/core/Loader.php +++ b/flight/core/Loader.php @@ -13,8 +13,8 @@ use Exception; * instances with custom initialization parameters. It also performs * class autoloading. * - * @license MIT, http://flightphp.com/license - * @copyright Copyright (c) 2011, Mike Cao + * @copyright 2011 [Mike Cao](https://mikecao.com) + * @license https://docs.flightphp.com/license MIT */ class Loader { diff --git a/flight/net/Request.php b/flight/net/Request.php index 24f02a5..fadd956 100644 --- a/flight/net/Request.php +++ b/flight/net/Request.php @@ -11,8 +11,8 @@ use flight\util\Collection; * all the super globals $_GET, $_POST, $_COOKIE, and $_FILES * are stored and accessible via the Request object. * - * @license MIT, http://flightphp.com/license - * @copyright Copyright (c) 2011, Mike Cao + * @copyright 2011 [Mike Cao](https://mikecao.com) + * @license https://docs.flightphp.com/license MIT * * The default request properties are: * diff --git a/flight/net/Response.php b/flight/net/Response.php index 1a738cf..883bb9c 100644 --- a/flight/net/Response.php +++ b/flight/net/Response.php @@ -12,8 +12,8 @@ use flight\core\EventDispatcher; * contains the response headers, HTTP status code, and response * body. * - * @license MIT, http://flightphp.com/license - * @copyright Copyright (c) 2011, Mike Cao + * @copyright 2011 [Mike Cao](https://mikecao.com) + * @license https://docs.flightphp.com/license MIT */ class Response { diff --git a/flight/net/Route.php b/flight/net/Route.php index 47f93dc..434bfca 100644 --- a/flight/net/Route.php +++ b/flight/net/Route.php @@ -9,8 +9,8 @@ namespace flight\net; * an assigned callback function. The Router tries to match the * requested URL against a series of URL patterns. * - * @license MIT, http://flightphp.com/license - * @copyright Copyright (c) 2011, Mike Cao + * @copyright 2011 [Mike Cao](https://mikecao.com) + * @license https://docs.flightphp.com/license MIT */ class Route { diff --git a/flight/net/Router.php b/flight/net/Router.php index 0ec9724..a5d5150 100644 --- a/flight/net/Router.php +++ b/flight/net/Router.php @@ -12,8 +12,8 @@ use flight\net\Route; * an assigned callback function. The Router tries to match the * requested URL against a series of URL patterns. * - * @license MIT, http://flightphp.com/license - * @copyright Copyright (c) 2011, Mike Cao + * @copyright 2011 [Mike Cao](https://mikecao.com) + * @license https://docs.flightphp.com/license MIT */ class Router { diff --git a/flight/template/View.php b/flight/template/View.php index f995d36..758777a 100644 --- a/flight/template/View.php +++ b/flight/template/View.php @@ -9,8 +9,8 @@ namespace flight\template; * methods for managing view data and inserts the data into * view templates upon rendering. * - * @license MIT, http://flightphp.com/license - * @copyright Copyright (c) 2011, Mike Cao + * @copyright 2011 [Mike Cao](https://mikecao.com) + * @license https://docs.flightphp.com/license MIT */ class View { diff --git a/flight/util/Collection.php b/flight/util/Collection.php index e17ed37..17142e9 100644 --- a/flight/util/Collection.php +++ b/flight/util/Collection.php @@ -13,10 +13,10 @@ use JsonSerializable; * The Collection class allows you to access a set of data * using both array and object notation. * - * @license MIT, http://flightphp.com/license - * @copyright Copyright (c) 2011, Mike Cao + * @copyright 2011 [Mike Cao](https://mikecao.com) * @implements ArrayAccess * @implements Iterator + * @license https://docs.flightphp.com/license MIT */ class Collection implements ArrayAccess, Iterator, Countable, JsonSerializable { From 32ff66428dbc67327f17fc6492b17c20e02f768b Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Fri, 14 Aug 2026 02:11:14 -0400 Subject: [PATCH 13/25] use raw copyright links for compatibility --- flight/Engine.php | 8 ++------ flight/Flight.php | 7 ++----- flight/core/Dispatcher.php | 2 +- flight/core/Loader.php | 2 +- flight/net/Request.php | 2 +- flight/net/Response.php | 2 +- flight/net/Route.php | 2 +- flight/net/Router.php | 2 +- flight/template/View.php | 2 +- flight/util/Collection.php | 2 +- 10 files changed, 12 insertions(+), 19 deletions(-) diff --git a/flight/Engine.php b/flight/Engine.php index 880decf..ac56867 100644 --- a/flight/Engine.php +++ b/flight/Engine.php @@ -24,8 +24,7 @@ use Psr\Container\ContainerInterface; * It is responsible for loading an HTTP request, running the assigned services, * and generating an HTTP response. * - * @license MIT, https://docs.flightphp.com/license - * @copyright Copyright (c) 2011-2025, Mike Cao , n0nag0n + * @copyright 2011-2026, Mike Cao https://mikecao.com, n0nag0n * * @method void start() * @method void stop() @@ -75,10 +74,7 @@ use Psr\Container\ContainerInterface; * @phpstan-method void json(mixed $data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512) * @phpstan-method void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0) * @phpstan-method void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512) - * - * Note: IDEs will use standard @method tags for autocompletion, while PHPStan will use @phpstan-* tags for advanced type checking. - * - * phpcs:disable PSR2.Methods.MethodDeclaration.Underscore + * @license https://docs.flightphp.com/license MIT */ class Engine { diff --git a/flight/Flight.php b/flight/Flight.php index ddb536f..b975197 100644 --- a/flight/Flight.php +++ b/flight/Flight.php @@ -15,7 +15,7 @@ use Psr\Container\ContainerInterface; * The Flight class is a static representation of the framework. * * @license MIT, https://docs.flightphp.com/license - * @copyright Copyright (c) 2011-2025, Mike Cao , n0nag0n + * @copyright 2011-2026, Mike Cao https://mikecao.com, n0nag0n * * @method static void start() * @method static void path(string $dir) @@ -77,11 +77,8 @@ use Psr\Container\ContainerInterface; * @phpstan-method static void json(mixed $data, int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512) * @phpstan-method static void jsonHalt(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0) * @phpstan-method static void jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = "utf8", int $encodeOption = 0, int $encodeDepth = 512) - * - * Note: IDEs will use standard @method tags for autocompletion, - * while PHPStan will use @phpstan-* tags for advanced type checking. + * @license https://docs.flightphp.com/license MIT */ -// phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace class Flight { /** diff --git a/flight/core/Dispatcher.php b/flight/core/Dispatcher.php index f0f5b2a..ea25e60 100644 --- a/flight/core/Dispatcher.php +++ b/flight/core/Dispatcher.php @@ -18,7 +18,7 @@ use TypeError; * allows you to hook other functions to an event that can modify the * input parameters and/or the output. * - * @copyright 2011 [Mike Cao](https://mikecao.com) + * @copyright 2011 Mike Cao https://mikecao.com * @license https://docs.flightphp.com/license MIT * @phpstan-template EngineTemplate of object */ diff --git a/flight/core/Loader.php b/flight/core/Loader.php index 63bafd9..a3f52cb 100644 --- a/flight/core/Loader.php +++ b/flight/core/Loader.php @@ -13,7 +13,7 @@ use Exception; * instances with custom initialization parameters. It also performs * class autoloading. * - * @copyright 2011 [Mike Cao](https://mikecao.com) + * @copyright 2011 Mike Cao https://mikecao.com * @license https://docs.flightphp.com/license MIT */ class Loader diff --git a/flight/net/Request.php b/flight/net/Request.php index fadd956..a2dcb48 100644 --- a/flight/net/Request.php +++ b/flight/net/Request.php @@ -11,7 +11,7 @@ use flight\util\Collection; * all the super globals $_GET, $_POST, $_COOKIE, and $_FILES * are stored and accessible via the Request object. * - * @copyright 2011 [Mike Cao](https://mikecao.com) + * @copyright 2011 Mike Cao https://mikecao.com * @license https://docs.flightphp.com/license MIT * * The default request properties are: diff --git a/flight/net/Response.php b/flight/net/Response.php index 883bb9c..cd0e2a1 100644 --- a/flight/net/Response.php +++ b/flight/net/Response.php @@ -12,7 +12,7 @@ use flight\core\EventDispatcher; * contains the response headers, HTTP status code, and response * body. * - * @copyright 2011 [Mike Cao](https://mikecao.com) + * @copyright 2011 Mike Cao https://mikecao.com * @license https://docs.flightphp.com/license MIT */ class Response diff --git a/flight/net/Route.php b/flight/net/Route.php index 434bfca..d27df37 100644 --- a/flight/net/Route.php +++ b/flight/net/Route.php @@ -9,7 +9,7 @@ namespace flight\net; * an assigned callback function. The Router tries to match the * requested URL against a series of URL patterns. * - * @copyright 2011 [Mike Cao](https://mikecao.com) + * @copyright 2011 Mike Cao https://mikecao.com * @license https://docs.flightphp.com/license MIT */ class Route diff --git a/flight/net/Router.php b/flight/net/Router.php index a5d5150..770ab9c 100644 --- a/flight/net/Router.php +++ b/flight/net/Router.php @@ -12,7 +12,7 @@ use flight\net\Route; * an assigned callback function. The Router tries to match the * requested URL against a series of URL patterns. * - * @copyright 2011 [Mike Cao](https://mikecao.com) + * @copyright 2011 Mike Cao https://mikecao.com * @license https://docs.flightphp.com/license MIT */ class Router diff --git a/flight/template/View.php b/flight/template/View.php index 758777a..fae471f 100644 --- a/flight/template/View.php +++ b/flight/template/View.php @@ -9,7 +9,7 @@ namespace flight\template; * methods for managing view data and inserts the data into * view templates upon rendering. * - * @copyright 2011 [Mike Cao](https://mikecao.com) + * @copyright 2011 Mike Cao https://mikecao.com * @license https://docs.flightphp.com/license MIT */ class View diff --git a/flight/util/Collection.php b/flight/util/Collection.php index 17142e9..5b2c4a3 100644 --- a/flight/util/Collection.php +++ b/flight/util/Collection.php @@ -13,7 +13,7 @@ use JsonSerializable; * The Collection class allows you to access a set of data * using both array and object notation. * - * @copyright 2011 [Mike Cao](https://mikecao.com) + * @copyright 2011 Mike Cao https://mikecao.com * @implements ArrayAccess * @implements Iterator * @license https://docs.flightphp.com/license MIT From 4c2a08c3e6c86a7da160cea21fa8f0e08b2e6d46 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 01:45:41 -0400 Subject: [PATCH 14/25] remove reduntant EventDispatcher::$instance description --- flight/core/EventDispatcher.php | 1 - 1 file changed, 1 deletion(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 8e60d1a..947d60a 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -6,7 +6,6 @@ namespace flight\core; class EventDispatcher { - /** @var self|null Singleton instance of the EventDispatcher */ private static ?self $instance = null; /** @var array> */ From 3066c5dcc459a790ac414f477eccbe29924206c7 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 01:46:10 -0400 Subject: [PATCH 15/25] simplify EventDispatcher listeners typehint --- flight/core/EventDispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 947d60a..98e79fb 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -8,7 +8,7 @@ class EventDispatcher { private static ?self $instance = null; - /** @var array> */ + /** @var array */ protected array $listeners = []; /** From 8d29ad4fd005e6f2cf46ff7b33ebaa3a591e77c2 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 01:47:07 -0400 Subject: [PATCH 16/25] remove reduntant EventDispatcher@getInstance description --- flight/core/EventDispatcher.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 98e79fb..1c84d26 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -11,16 +11,12 @@ class EventDispatcher /** @var array */ protected array $listeners = []; - /** - * Singleton instance of the EventDispatcher. - * - * @return self - */ public static function getInstance(): self { if (self::$instance === null) { self::$instance = new self(); } + return self::$instance; } From 3723228c3de7e81bf492eb29bde8dbebc847060d Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 01:49:24 -0400 Subject: [PATCH 17/25] simplify EventDispatcher@on --- flight/core/EventDispatcher.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 1c84d26..a7e2f75 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -20,17 +20,9 @@ class EventDispatcher return self::$instance; } - /** - * Register a callback for an event. - * - * @param string $event Event name - * @param callable $callback Callback function - */ public function on(string $event, callable $callback): void { - if (isset($this->listeners[$event]) === false) { - $this->listeners[$event] = []; - } + $this->listeners[$event] ??= []; $this->listeners[$event][] = $callback; } From f7b2736736e1f463a7b0bf6235fb16ada2dfb417 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 01:56:53 -0400 Subject: [PATCH 18/25] simplify EventDispatcher@trigger --- flight/core/EventDispatcher.php | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index a7e2f75..3476192 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -27,27 +27,24 @@ class EventDispatcher } /** - * Trigger an event with optional arguments. - * - * @param string $event Event name - * @param mixed ...$args Arguments to pass to the callbacks - * + * @param mixed ...$args Arguments to pass to the listeners. * @return mixed */ public function trigger(string $event, ...$args) { - $result = null; - if (isset($this->listeners[$event]) === true) { - foreach ($this->listeners[$event] as $callback) { - $result = call_user_func_array($callback, $args); + $listenerReturnValue = null; + + if (isset($this->listeners[$event])) { + foreach ($this->listeners[$event] as $listener) { + $listenerReturnValue = $listener(...$args); - // If you return false, it will break the loop and stop the other event listeners. - if ($result === false) { - break; // Stop executing further listeners + if ($listenerReturnValue === false) { + break; } } } - return $result; + + return $listenerReturnValue; } /** From 0d50ed97d671160c58e79f591df6dbe9c8c4046e Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 01:58:22 -0400 Subject: [PATCH 19/25] use early returns in EventDispatcher@trigger --- flight/core/EventDispatcher.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 3476192..cf361ca 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -34,13 +34,15 @@ class EventDispatcher { $listenerReturnValue = null; - if (isset($this->listeners[$event])) { - foreach ($this->listeners[$event] as $listener) { - $listenerReturnValue = $listener(...$args); + if (!isset($this->listeners[$event])) { + return null; + } + + foreach ($this->listeners[$event] as $listener) { + $listenerReturnValue = $listener(...$args); - if ($listenerReturnValue === false) { - break; - } + if ($listenerReturnValue === false) { + break; } } From 6bc62d9b0ce6bc6a9cf7082a204573abb802561f Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 02:00:25 -0400 Subject: [PATCH 20/25] simplify EventDispatcher@hasListeners --- flight/core/EventDispatcher.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index cf361ca..b264a1a 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -49,16 +49,13 @@ class EventDispatcher return $listenerReturnValue; } - /** - * Check if an event has any registered listeners. - * - * @param string $event Event name - * - * @return bool True if the event has listeners, false otherwise - */ public function hasListeners(string $event): bool { - return isset($this->listeners[$event]) === true && count($this->listeners[$event]) > 0; + return ( + isset($this->listeners[$event]) + && is_array($this->listeners[$event]) + && count($this->listeners[$event]) + ); } /** From 4abcd23e117c82c7841ea23f88f22c705ae98aba Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 02:01:21 -0400 Subject: [PATCH 21/25] use EventDispatcher@hasListeners in trigger --- flight/core/EventDispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index b264a1a..054dc75 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -34,7 +34,7 @@ class EventDispatcher { $listenerReturnValue = null; - if (!isset($this->listeners[$event])) { + if (!$this->hasListeners($event)) { return null; } From 361e45e9743c1f4b12792528a4e72ffdcd596eaa Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 02:03:00 -0400 Subject: [PATCH 22/25] simplify EventDispatcher@getListeners --- flight/core/EventDispatcher.php | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 054dc75..4f5c71a 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -34,11 +34,7 @@ class EventDispatcher { $listenerReturnValue = null; - if (!$this->hasListeners($event)) { - return null; - } - - foreach ($this->listeners[$event] as $listener) { + foreach ($this->getListeners($event) as $listener) { $listenerReturnValue = $listener(...$args); if ($listenerReturnValue === false) { @@ -58,13 +54,7 @@ class EventDispatcher ); } - /** - * Get all listeners registered for a specific event. - * - * @param string $event Event name - * - * @return array Array of callbacks registered for the event - */ + /** @return callable[] */ public function getListeners(string $event): array { return $this->listeners[$event] ?? []; From 6c22bad3f0e9428799a584d33a5150e44daf6b61 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 02:04:34 -0400 Subject: [PATCH 23/25] remove redundant explanation of EventDispatcher@getAllRegisteredEvents --- flight/core/EventDispatcher.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 4f5c71a..6884d33 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -60,11 +60,7 @@ class EventDispatcher return $this->listeners[$event] ?? []; } - /** - * Get a list of all events that have registered listeners. - * - * @return array Array of event names - */ + /** @return string[] */ public function getAllRegisteredEvents(): array { return array_keys($this->listeners); From 4cb50f66ab8b442d7167800cbe1a1f6316f5cc1d Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 02:09:14 -0400 Subject: [PATCH 24/25] simplify EventDispatcher@removeListener --- flight/core/EventDispatcher.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 6884d33..3b66a2c 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -66,22 +66,16 @@ class EventDispatcher return array_keys($this->listeners); } - /** - * Remove a specific listener for an event. - * - * @param string $event the event name - * @param callable $callback the exact callback to remove - * - * @return void - */ public function removeListener(string $event, callable $callback): void { - if (isset($this->listeners[$event]) === true && count($this->listeners[$event]) > 0) { - $this->listeners[$event] = array_filter($this->listeners[$event], function ($listener) use ($callback) { - return $listener !== $callback; - }); - $this->listeners[$event] = array_values($this->listeners[$event]); // Re-index the array + if (!$this->hasListeners($event)) { + return; } + + $this->listeners[$event] = array_values(array_filter( + $this->getListeners($event), + static fn(callable $listener): bool => $listener !== $callback, + )); } /** From cd3d8bb44ef3cdf4cc170b60f02ce92a0f5126d2 Mon Sep 17 00:00:00 2001 From: fadrian06 Date: Sun, 16 Aug 2026 02:10:49 -0400 Subject: [PATCH 25/25] simplify EventDispatcher@removeAllListeners and resetInstance --- flight/core/EventDispatcher.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/flight/core/EventDispatcher.php b/flight/core/EventDispatcher.php index 3b66a2c..1a63731 100644 --- a/flight/core/EventDispatcher.php +++ b/flight/core/EventDispatcher.php @@ -78,25 +78,11 @@ class EventDispatcher )); } - /** - * Remove all listeners for a specific event. - * - * @param string $event the event name - * - * @return void - */ public function removeAllListeners(string $event): void { - if (isset($this->listeners[$event]) === true) { - unset($this->listeners[$event]); - } + unset($this->listeners[$event]); } - /** - * Remove the current singleton instance of the EventDispatcher. - * - * @return void - */ public static function resetInstance(): void { self::$instance = null;