symfony/phpunit-bridge
PHPUnit Bridge adds utilities on top of PHPUnit, with a focus on managing deprecation notices in your test suite. It helps you track, report, and fix deprecations so your code stays compatible with future Symfony and PHP versions.
Architecture fit
symfony/phpunit-bridge is dev-only test infrastructure — it belongs in require-dev and never ships to production. For a Laravel/PHP codebase this means zero runtime coupling, no autoload cost in the request lifecycle, and no production failure surface. That is the single most important fit signal: the adoption risk is bounded to CI.symfony/console, http-foundation, finder, process, error-handler, var-dumper, mime, translation, polyfill-*). The bridge therefore lands in a dependency graph that already exists rather than introducing a new vendor. The real constraint is major-version alignment: Laravel 10/11 pins Symfony ^6.2/^7.0, while bridge v8 requires PHP ≥ 8.4. A team on PHP 8.2 must resolve to the 7.x bridge line, and that choice will be dictated by the framework's own transitive constraints — not by preference.--display-deprecations / --fail-on-deprecation, and symfony/deprecation-contracts supplies trigger_deprecation(). The bridge's incremental value for a Laravel team is narrower than the README implies: grouped/deduplicated deprecation reporting with configurable baselines and thresholds (SYMFONY_DEPRECATIONS_HELPER), ExpectUserDeprecationMessageTrait, and ClockMock/DnsMock for tests that touch native time(), strtotime(), sleep(), or dns_get_record() — i.e. functions Carbon's setTestNow() and Http::fake() cannot intercept.Integration feasibility
bootstrap.php and patched Symfony's TestCase; recent changelogs ("Skip bootstrap for PHPUnit >= 10", "Fix TestCase patching") confirm much of that machinery is legacy path and inert on modern PHPUnit. Laravel's Tests\TestCase extends Illuminate\Foundation\Testing\TestCase, not Symfony's, so TestCase-patching features are irrelevant to us and the deprecation listener must work purely through the error handler. That must be validated empirically, not assumed from the README.Technical risk
vendor/, PSR-0/PSR-4 fallback dirs, config-file discovery). Containerized CI with bind mounts or vendor/ symlinks is exactly the environment that trips this.php artisan test --parallel, Paratest) — verify deprecation aggregation and baseline state across workers before enabling enforcement.Dependents: 0 is an artifact of Symfony's monorepo split — real-world adoption is effectively universal in the Symfony ecosystem. Do not read it as a signal.Key questions
withoutExceptionHandling() and Laravel's HandleExceptions bootstrapper?vendor/ behind a symlink or bind mount?Stack fit
phpunit.xml pattern, one CI threshold policy. Because Laravel apps in an org typically share a skeleton, this is a template-level change, not an N-app change.ClockMock/DnsMock/ExpectUserDeprecationMessageTrait as opt-in per test, adopted only where a concrete flaky-or-untestable case exists. Do not mandate them.Migration path
require-dev, run the full suite, capture deprecation output. Explicitly test in the containerized CI image. Success = suite green with reporting on and zero change in pass/fail semantics.SYMFONY_DEPRECATIONS_HELPER to fail on new direct deprecations only; exclude vendor paths. Publish the escape hatch (@group legacy equivalent) so teams aren't blocked.ClockMock/DnsMock recipes; adopt where flakiness data justifies it.composer remove plus a phpunit.xml revert. This is the cheapest possible rollback story and should be stated as such to stakeholders.Compatibility
^7.4 || ^8.0) and resolved by Composer against the app's PHP floor. Avoid hard-pinning a major that conflicts with Laravel's symfony/* requirements — that yields resolution failures that look like the bridge is "broken."Maintenance
symfony/symfony monorepo rather than a dedicated backlog. Internal ownership must therefore be explicit: assign the test-infrastructure/DevEx team as the single owner of the constraint, the CI threshold, and the runbook.Support
Scaling
Failure modes
composer update. Mitigate by scoping to direct deprecations and excluding vendor/.vendor/ in CI containers — presents as missing baseline or wrong file paths, easily misdiagnosed as a config error.Carbon::setTestNow() and ClockMock disagree, producing tests that pass locally and fail in CI (or vice versa).Ramp-up
How can I help you explore Laravel packages today?