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

Global State Laravel Package

sebastian/global-state

Snapshot and restore PHP global state with sebastian/global-state, the standalone component extracted from PHPUnit. Capture globals, superglobals, static properties, and constants for reliable test isolation.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit: Program-level test tooling, not a product dependency. sebastian/global-state is a stand-alone extraction of PHPUnit's own test-isolation machinery — it snapshots $GLOBALS, superglobals, and static properties, then compares/restores them so tests don't leak state into one another. That places it squarely in the development-dependency tier, never on the production autoload path. For a Laravel program it has no architectural seam: RefreshDatabase, per-test application instances, container rebinding, Facade::clearResolvedInstances(), and the fake() helpers already cover the leakage categories most feature tests produce. The defensible fits are narrow and specific — a shared base TestCase, an internal test-harness package, or a non-PHPUnit runner (custom CLI harness, worker loop needing deterministic resets between iterations). Record it in the dependency register as inherited dev tooling; do not treat it as an architecture decision requiring sign-off.

Integration feasibility: Mechanically trivial, organizationally a governance question. A composer require --dev plus a Snapshot::snapshot() / Restorer pair behind a trait is roughly half a day for one engineer. The cost that matters at program level is that declaring the dependency directly converts a free transitive pin into an explicitly owned one: your team then fields the upgrade tickets when the PHP support window shifts, rather than riding PHPUnit's. Feasibility is high; discretionary value is low; the correct posture is "adopt explicitly only with a measured problem and a named owner," not "adopt because it's cheap."

Technical risk: Low for correct test-only use, meaningful for drift and misuse. Four items belong in the risk register:

  • Version-matrix drift. Support windows move in lockstep with PHPUnit majors (v9 removes PHP 8.3 support; v8.x targets 8.0–8.2; v7.x spans 8.1–8.3). Because it rides transitively today, its window silently becomes a constraint on the platform PHP upgrade train — a coupling most teams meet mid-upgrade.
  • Misuse in runtime code. Restoring $_ENV/$_SERVER/$_SESSION outside test teardown is a stability and security concern, not a testing convenience. Any usage outside tests/ is a stop-work signal.
  • Silent under-capture. Reflection-based static capture sees declared properties and user-defined constants only; dynamic properties and internal object state escape. Tests go green while state leaks — worse than a visible failure because it erodes trust in the suite as a signal.
  • Concurrency. Full-snapshot restore mutates process-wide state; under Paratest the restore semantics need explicit validation rather than assumption.

The adoption signal is a flag rather than reassurance: ~6.6k stars with effectively zero direct dependents means the install base is almost entirely transitive via PHPUnit, and README-only documentation means the API contract is whatever the source says it is.

Key questions:

  • Do we have a measured flake rate attributable to global/static leakage, or are we pre-optimizing against a hypothetical?
  • What version does Composer currently resolve for us, and what pin does that inherit from phpunit/phpunit?
  • Are we running parallel tests, where restore semantics become a correctness issue rather than a cleanup nicety?
  • What leakage classes does our suite exhibit that Laravel's isolation does not cover — legacy superglobal code, static caches, singleton services?
  • Who is the named owner of test infrastructure, and is that a bus factor of one?
  • Is any team reaching for this outside tests/?

Integration Approach

Stack fit: Development dependency only, contained behind a thin wrapper. Wrap it in a small GlobalStateIsolation trait or base-class hook (~50 lines) so the package stays an implementation detail and engineers never call it directly. Use try/finally semantics rather than relying on tearDown ordering — teardown order is exactly what breaks when another team inserts a base class between you and the framework. Default to selective snapshots (['globals' => ['$_ENV']]) rather than full captures, so the fast path is also the easy path.

Migration path: Do not schedule speculative adoption. The defensible sequence:

  1. Leave the transitive dependency alone; manage PHPUnit's pin as the real control point.
  2. Instrument CI (repeat runs, random order, --order-by=random) and classify flaky failures by root cause. Publish the baseline flake rate and suite duration.
  3. Only where global/static leakage is confirmed as the cause, add the explicit dev dependency and apply selective snapshots.
  4. Consolidate into the shared base test case once proven on one suite, then roll to additional suites behind a documented exclusion list.

Compatibility: The binding constraint is the PHP matrix, not Laravel. Validate the resolved version against the target Laravel release's minimum PHP before writing code, and re-validate at every Laravel, PHP, or PHPUnit major — treat it as a gate item in upgrade checklists, not a footnote. Patch-level behaviour has shifted too (superglobal handling changed in 8.0.1/8.0.2; constant-name escaping fixed in 8.0.3/9.0.1), so selective-snapshot arrays need per-version verification rather than copy-paste from a blog post.

Sequencing: Spike in one high-flake suite and record before/after numbers → wrap usage → measure again → keep only if flake rate drops without a meaningful runtime regression → roll to the shared base case. Keep the whole effort inside a single sprint and a single squad; this does not warrant multi-team coordination. The one piece of cross-team work worth funding is the inventory and classification step in item 2 — it produces durable value (a flake taxonomy and a CI gate) even if you never adopt the package directly.

Milestone gates for the program plan:

  • Gate 1 (assess): baseline flake rate and root-cause classification published.
  • Gate 2 (spike): one suite instrumented; runtime delta measured against a stated tolerance.
  • Gate 3 (standardize): wrapper in the shared base case, exclusion list documented in the repo, owner assigned.
  • Kill criterion: if no confirmed leakage-attributable failures exist, close the item and consume it transitively. That is a successful outcome, not a shelved initiative.

Operational Impact

Maintenance: Near-zero direct cost — actively released (latest 2026-06-01) and maintained alongside PHPUnit by the same author. The indirect cost is the real line item: every PHPUnit major forces a compatible-bump review, and this package's breaking changes ship on that cadence rather than ours. Budget a recurring entry in every test-infrastructure and PHP-upgrade cycle, and track its support window on the same roadmap lane as the platform PHP version.

Support: Community and upstream only — no commercial backing, no LTS commitment beyond the maintainer's own policy. Knowledge will concentrate in whoever writes the wrapper. Mitigate structurally: keep the wrapper small enough to rewrite in an afternoon, document its contract and default exclusions (notably $_SESSION and $_COOKIE) in the repo, and record the transitive pin in the dependency register so a future maintainer can answer "why is this version locked?" without archaeology.

Scaling: Snapshot cost scales with suite size × $GLOBALS size × object-graph complexity. Selective snapshots are the primary lever — enforce them as the wrapper default. Parallel execution is the scaling hazard: restore touches process-wide state, so correctness under Paratest must be proven with a repeat-run soak, not inferred from a green local build. Watch long-running suite memory, as snapshotted object graphs retain references between runs.

Failure modes: Silent under-capture (dynamic properties and internal object state escape the snapshot, producing tests that pass locally and leak in CI) · session/cookie races under concurrency · Composer resolution breaking on a PHP upgrade because the transitive pin moved underneath us · memory retention from large snapshotted graphs inflating long-running suite memory · and the organizational failure mode — over-adoption becoming cover for leaving global-state design problems unfixed in production code. That last one is the TPM-relevant risk: a test-suite workaround is not a remediation plan, and it resurfaces later as an incident or an unplanned refactor.

Ramp-up: Low. Any engineer fluent in PHPUnit can use the snapshot/restore pair within an hour; the non-obvious learning is what is excluded by default and why selective snapshots matter, which is a one-page internal doc plus a code-review convention, not a training program. Keep the wrapper opinionated so correct usage is the path of least resistance, and ramp-up stays a non-issue at program scale.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource