dg/bypass-finals
DG\BypassFinals lets you bypass PHP’s final classes and methods at runtime so you can mock, extend, or patch code that’s otherwise locked down—useful for testing legacy dependencies. Lightweight, Composer-ready, and works with popular test frameworks.
final classes (e.g., SDKs, legacy dependencies) that block mocking in unit/integration tests.final services (e.g., Symfony components, Laravel\Foundation\Application internals).tests/bootstrap.php), unlike Laravel’s built-in testing utilities.phpunit runs) to avoid runtime errors.final removal may bypass Laravel’s compiled bytecode optimizations).dev dependency.tests/bootstrap.php or phpunit.xml).final bindings like App\Providers\RouteServiceProvider).final classes in frontend integration tests).readonly support: Unclear if the package handles readonly properties correctly in newer PHP versions (last release tested in PHP 8.2).opcache.enable=0 in CI.final may mask actual runtime behavior differences (e.g., final methods enforcing immutability).NOASSERTION license acceptable for our project? If not, can we fork and relicense?final causes silent test failures (e.g., final methods with side effects)?make:mock or Pest’s mocking helpers?final facades (e.g., Route::finalMethod())?PHPUnitExtension.createMock() or mock() syntax.tests/bootstrap.php.composer install --no-dev (use --dev flag).vendor/ outside test environments.composer require --dev dg/bypass-finals
phpunit.xml (recommended for isolation):
<php>
<autoDiscover>false</autoDiscover>
<bootstrap>tests/bootstrap.php</bootstrap>
</php>
// tests/bootstrap.php
if (!app()->runningInConsole()) return; // Safety check
(new \BypassFinals\Loader())->register();
TestCase (less isolated):
// app/Providers/AppServiceProvider.php
if (app()->environment('testing')) {
(new \BypassFinals\Loader())->register();
}
final classes:
$mock = $this->createMock(\FinalVendor\Class::class);
$mock->method('finalMethod')->willReturn('mocked');
| Component | Compatibility | Notes |
|---|---|---|
| Laravel 8–11 | ✅ Yes (PHP 7.4–8.3) | Test PHP 8.2+ readonly behavior. |
| PHPUnit 9–10 | ✅ Yes | Uses PHPUnitExtension. |
| Mockery 1.x | ✅ Yes | Works with mock() syntax. |
| Pest 2.x | ✅ Yes (indirectly) | Use mock() helper. |
| OPcache | ⚠️ May conflict | Disable in CI (opcache.enable=0). |
| Laravel Service Container | ⚠️ Partial | Can mock final bindings, but may need manual DI tweaks. |
composer.json under require-dev.tests/bootstrap.php before autoloading.final classes.vendor/ in CI).NOASSERTION may require forking for corporate use.readonly features).Rewriter).BypassFinals::debugInfo() to log rewrites.final classes to reduce blast radius.memory_limit=-1 in CI).--parallel.| Scenario | Risk | Mitigation |
|---|---|---|
| Production leakage | Runtime errors (e.g., final removal breaks type safety). |
CI checks for dg/bypass-finals in vendor/. |
| False test passes | Mocks hide actual final behavior. |
Pair with property-based testing. |
| OPcache conflicts | Stale bytecode causes tests to fail. | Disable OPcache in test environments. |
| ** |
How can I help you explore Laravel packages today?