Weave Code
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

sebastian/global-state snapshots and restores PHP global state (globals, superglobals, ini settings, etc.), extracted from PHPUnit as a standalone component. Useful for test isolation and detecting side effects by capturing state before and after code runs.

View on GitHub
Deep Wiki
Context7

Getting Started

Install as a dev dependency:

composer require --dev sebastian/global-state

First use case: Isolate tests modifying global state (e.g., $_ENV, $_SERVER, or static properties). Initialize in your test's setUp():

use SebastianBergmann\GlobalState\Snapshot;

class MyTest extends TestCase
{
    private Snapshot $snapshot;

    protected function setUp(): void
    {
        $this->snapshot = Snapshot::snapshot(); // Capture current state
    }

    protected function tearDown(): void
    {
        $this->snapshot->restore(); // Reset to captured state
    }
}

Where to look first:


Implementation Patterns

1. Test Isolation Workflow

// Before test: Capture state
$snapshot = Snapshot::snapshot();

// During test: Modify globals/statics
$_ENV['TEST_VAR'] = 'modified';
MyClass::$staticVar = 'new_value';

// After test: Restore
$snapshot->restore(); // $_ENV and static revert to original

2. Selective Snapshotting (Performance)

// Only snapshot $_GET and $_POST (skip $_SESSION for speed)
$snapshot = Snapshot::snapshot([
    'superGlobals' => ['$_GET', '$_POST'],
]);

3. Static Properties in Custom Classes

// Snapshot statics for App\Services\Cache
$snapshot = Snapshot::snapshot([
    'staticProperties' => ['App\Services\Cache::class'],
]);

4. Integration with Laravel’s TestCase

Extend Laravel’s TestCase and override setUp():

use Illuminate\Foundation\Testing\TestCase as LaravelTestCase;
use SebastianBergmann\GlobalState\Snapshot;

class MyTest extends LaravelTestCase
{
    private Snapshot $snapshot;

    protected function setUp(): void
    {
        parent::setUp();
        $this->snapshot = Snapshot::snapshot(['superGlobals' => ['$_SERVER']]);
    }

    protected function tearDown(): void
    {
        $this->snapshot->restore();
        parent::tearDown();
    }
}

5. Non-PHPUnit Use Cases

  • CLI scripts: Reset $_ENV between command runs.
  • Swoole/Lumen: Restore state between requests in long-running processes.
  • Legacy code: Isolate tests for code relying on $GLOBALS or register_shutdown_function().

Gotchas and Tips

Pitfalls

  1. PHP Version Lock-in:

    • v9.x drops PHP 8.3 support. Upgrade PHP? Check Laravel’s supported versions and align with sebastian/global-state’s release notes.
    • Workaround: Pin to 8.x in composer.json if using PHP 8.2:
      "require-dev": {
          "sebastian/global-state": "^8.0"
      }
      
  2. Super-Global Exclusions:

    • $_SESSION and $_COOKIE are not snapshotted by default (risk of race conditions in concurrent tests).
    • Fix: Explicitly include them, but avoid in CI where sessions may be shared:
      Snapshot::snapshot(['superGlobals' => ['$_SESSION']]); // Use cautiously!
      
  3. Static Property Limitations:

    • Only declared static properties are captured. Dynamic additions (e.g., $obj->static = 'value') are ignored.
    • Tip: Use ReflectionClass to verify statics before snapshotting.
  4. Performance Spikes:

    • Snapshotting $GLOBALS or large arrays (e.g., $_SERVER with 100+ keys) adds overhead.
    • Optimization: Selectively snapshot only what’s needed:
      Snapshot::snapshot(['globals' => ['$_ENV', '$_SERVER']]);
      
  5. PHPUnit Redundancy:

    • PHPUnit ≥10 uses this internally. Overusing it in tests may indicate:
      • Poor test design (e.g., testing global state directly).
      • Missing dependency injection (e.g., hardcoding $_SERVER['REQUEST_METHOD']).
    • Best Practice: Prefer mocking services (e.g., Http::fake() in Laravel) over global snapshotting.

Debugging Tips

  • Verify Restored State:

    $snapshot = Snapshot::snapshot();
    $_ENV['TEST'] = 'value';
    $snapshot->restore();
    $this->assertNull($_ENV['TEST'] ?? null, 'State not restored!');
    
  • Inspect Captured State:

    $snapshot = Snapshot::snapshot();
    $state = $snapshot->getState(); // Debug array of captured values
    
  • Handle Early Test Failures:

    try {
        $snapshot = Snapshot::snapshot();
        // Test logic...
    } finally {
        $snapshot?->restore(); // Ensures cleanup even if test fails early
    }
    

Extension Points

  1. Custom State Providers: Override Snapshot::snapshot() to add support for non-standard globals (e.g., custom App::bind() entries):

    $snapshot = Snapshot::snapshot(['custom' => ['App\StateManager::getAll()']]);
    
  2. Post-Restore Callbacks: Extend Snapshot to run logic after restoration (e.g., log state changes):

    $snapshot = new Snapshot(...);
    $snapshot->restore();
    $snapshot->afterRestore(function() {
        Log::info('State restored at ' . now());
    });
    
  3. Laravel Service Provider: Register a global test helper:

    // app/Providers/TestServiceProvider.php
    public function boot()
    {
        if ($this->app->environment('testing')) {
            $this->app->singleton('snapshot', function() {
                return Snapshot::snapshot(['superGlobals' => ['$_SERVER']]);
            });
        }
    }
    

    Usage in tests:

    $this->app['snapshot']->restore();
    

Laravel-Specific Quirks

  • Artisan Commands: Global state persists across Artisan commands. Use snapshots in handle():

    public function handle()
    {
        $snapshot = Snapshot::snapshot();
        // Command logic...
        $snapshot->restore();
    }
    
  • Queue Workers: Snapshots do not persist between queue jobs. Reset state per job:

    public function handle()
    {
        $snapshot = Snapshot::snapshot(['globals' => ['$_ENV']]);
        // Process job...
        $snapshot->restore();
    }
    
  • Testing Middleware: Avoid snapshotting $_SERVER if middleware relies on it (e.g., Accept header). Instead, mock the Request object:

    $this->withHeaders(['Accept' => 'application/json']);
    
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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle