Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phpunit Bridge Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

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.
  • Laravel already pulls Symfony components transitively (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.
  • The functionality overlaps partially with what Laravel/PHPUnit already give us: PHPUnit 10+ has --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

  • Installation is a one-line Composer dev dependency; opt-in adoption of individual traits/mocks is per-test-class. Feasible in a single sprint, spike-first.
  • The friction point is bootstrap and error-handler interplay, not installation. The bridge historically required its own 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

  • Medium-low, and entirely confined to CI. Ranked risks:
    1. Project-root / path resolution — a recurring upstream bug class (fixes for symlinked 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.
    2. Deprecation-noise amplification — a misconfigured threshold turns unrelated vendor deprecations into red builds. The bridge is a policy tool; without an agreed budget it becomes a blocker.
    3. Parallel test execution (php artisan test --parallel, Paratest) — verify deprecation aggregation and baseline state across workers before enabling enforcement.
    4. Patch-level churn — the release history shows dense, tiny patch releases (v8.1.1 → v8.1.9, with bugfixes landing across 5.4/6.4/7.x/8.x simultaneously). Low individual risk, high update noise.
    5. Data-quality caveat: the dataset's 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.
  • Maturity signal is maintainer, not popularity: Symfony core team, MIT, synchronized release trains, active backporting to 5.4/6.4/7.x, and a visible sponsorship appeal ("looking for a backer"). Funding signal, not abandonment signal.

Key questions

  • What is our PHP / PHPUnit version matrix per application, and which bridge major does each resolve to?
  • Do we actually need deprecation budgets, or does PHPUnit's native deprecation output already satisfy the upgrade-readiness goal?
  • Who owns triage of the deprecation baseline, and what is the ratchet policy?
  • Are we willing to add a second error handler to the test bootstrap, and has anyone verified it against withoutExceptionHandling() and Laravel's HandleExceptions bootstrapper?
  • Does our CI run vendor/ behind a symlink or bind mount?

Integration Approach

Stack fit

  • Target the platform/DevEx layer, not individual product teams: one shared Composer constraint, one documented 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.
  • Scope the initial ask to deprecation reporting + thresholds. Treat ClockMock/DnsMock/ExpectUserDeprecationMessageTrait as opt-in per test, adopted only where a concrete flaky-or-untestable case exists. Do not mandate them.

Migration path

  • Phase 0 — Spike (1 week, one repo): add as 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.
  • Phase 1 — Observe (2–4 weeks): enable grouped deprecation reporting, thresholds set to non-failing. Publish the baseline count. No developer-facing obligation.
  • Phase 2 — Enforce: ratchet 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.
  • Phase 3 — Optional tooling: document ClockMock/DnsMock recipes; adopt where flakiness data justifies it.
  • Reversibility: because it is dev-only and per-repo, rollback is a composer remove plus a phpunit.xml revert. This is the cheapest possible rollback story and should be stated as such to stakeholders.

Compatibility

  • Constraint should be expressed as a range matching the framework's transitive Symfony line (e.g. ^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."
  • Verify against the specific PHPUnit major in use; the "skip bootstrap for PHPUnit ≥ 10" behavior means the integration surface differs materially between PHPUnit 9.6 and 10/11. Treat these as two separate integration recipes in the runbook.
  • Sequencing: adopt before a Laravel or Symfony-component major upgrade (that is when it pays for itself), and not during one. Do not bundle it into a feature release train.

Operational Impact

Maintenance

  • Ongoing effort is low but non-zero: a dev dependency on a fast-moving, multi-branch release train. Expect Dependabot/Renovate noise at patch granularity; recommend a grouped-update policy with quarterly review rather than per-patch merging.
  • Upstream support is community-only — no SLA, no commercial vendor, issue tracker is the high-traffic 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

  • No production support surface (dev-only). Support burden is entirely internal enablement: interpreting deprecation reports and adjudicating "is this ours or vendor?" — a genuine ongoing cost if thresholds are enforced. Budget triage time; do not assume the tool is self-service.
  • Documentation risk: the README is a stub that links to Symfony's docs site. Onboarding leans on external documentation that tracks Symfony's roadmap, not Laravel's. Plan to write a short internal runbook rather than link out.

Scaling

  • Scales linearly and cheaply across repos via the shared skeleton. The friction at scale is social, not technical: a single org-wide threshold cannot fit a legacy app and a greenfield app simultaneously. Make thresholds configurable per repository with a documented floor.
  • Verify behavior under parallel/sharded test execution and split suites before enforcing; deprecation accounting across workers is the most likely scale-related surprise.

Failure modes

  • Silent no-op: on modern PHPUnit much of the bridge's legacy machinery is intentionally skipped — a team may believe enforcement is active when it is not. Validate with a deliberately introduced deprecation.
  • Red builds from vendor deprecations after a routine composer update. Mitigate by scoping to direct deprecations and excluding vendor/.
  • Path/root resolution failures under symlinked or bind-mounted vendor/ in CI containers — presents as missing baseline or wrong file paths, easily misdiagnosed as a config error.
  • Error-handler interference with Laravel's exception handling and PHPUnit's own error handler; surfaces as swallowed or duplicated failures.
  • Clock-mock confusion where Carbon::setTestNow() and ClockMock disagree, producing tests that pass locally and fail in CI (or vice versa).

Ramp-up

  • Engineering ramp-up is low (hours) for installation and reporting; moderate (one sprint of triage) to establish a meaningful baseline and threshold policy. No new language, framework, or runtime concept is introduced — the mental model is "PHPUnit plus a deprecation budget."
  • Recommended gate for go/no-go: spike passes in the containerized CI image, baseline captured, threshold policy written, and an owner named. Absent those four, the package adds CI risk without delivering its main benefit.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style