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

Php Autoload Override Laravel Package

adriansuter/php-autoload-override

Override fully qualified global function calls inside class methods so you can mock them in tests. Works with PHP 8.2+ and Composer PSR-4 autoloading; integrates via a PHPUnit bootstrap using OverrideFactory to map functions (e.g., rand) to real implementations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to Begin

  1. Installation:

    composer require --dev adriansuter/php-autoload-override ^2.0
    

    Ensure your project uses PSR-4 autoloading (PSR-0 is unsupported).

  2. Bootstrap Setup: In your tests/bootstrap.php, initialize overrides using OverrideFactory:

    use AdrianSuter\Autoload\Override\OverrideFactory;
    $classLoader = require __DIR__ . '/../vendor/autoload.php';
    OverrideFactory::create()
        ->forClass(\My\App\Probability::class, ['rand' => \rand(...)])
        ->apply($classLoader);
    
  3. First Test Case: Override \rand() in ProbabilityTest:

    use AdrianSuter\Autoload\Override\MockRegistry;
    MockRegistry::set(\My\App\Probability::class, 'rand', 35);
    $this->assertSame('blue', $probability->pick(34, 'red', 'blue'));
    

Where to Look First

  • Documentation: PHP-Autoload-Override Website
  • Source: Focus on OverrideFactory, MockRegistry, and Override classes in src/.
  • Examples: Review tests/ for real-world usage patterns.

Implementation Patterns

Core Workflow

  1. Define Overrides: Use OverrideFactory to chain overrides for multiple classes:

    OverrideFactory::create()
        ->forClass(\Clock::class, ['time' => \time(...)])
        ->forClass(\Probability::class, ['rand' => \rand(...)])
        ->apply($classLoader);
    
  2. Test Execution:

    • Set mocks before invoking the class under test:
      MockRegistry::set(\My\App\Class::class, 'function', $mockValue);
      
    • Reset mocks in tearDown() to avoid test pollution:
      protected function tearDown(): void {
          MockRegistry::reset(\My\App\Class::class);
      }
      
  3. Global Overrides: Use MockRegistry::setGlobal() for namespace-wide mocks (e.g., \time()):

    MockRegistry::setGlobal('time', 1234567890);
    

Integration Tips

  • Laravel-Specific: Place bootstrap logic in tests/TestCase.php or a dedicated TestServiceProvider:

    public function setUp(): void {
        parent::setUp();
        OverrideFactory::create()
            ->forClass(\App\Services\Payment::class, ['log' => fn($msg) => null])
            ->apply($this->app->get('autoload'));
    }
    
  • Dynamic Overrides: Build declarations dynamically in AbstractTestCase:

    protected function getOverrideDeclarations(): array {
        return OverrideFactory::create()
            ->forClass(\App\Models\User::class, ['str_random' => fn($len) => 'test'])
            ->build();
    }
    
  • Namespace-Level Overrides: Target entire namespaces (e.g., \App\Services\):

    Override::apply($classLoader, [
        'App\Services\' => ['log' => fn($msg) => null]
    ]);
    

Gotchas and Tips

Pitfalls

  1. PSR-4 Requirement: Fails silently with PSR-0 autoloading. Verify with:

    composer dump-autoload --optimize
    
  2. Closure Evaluation: Override closures are evaluated on every call unless guarded with MockRegistry::has():

    'rand' => function ($min, $max) {
        return MockRegistry::has(\Class::class, 'rand')
            ? MockRegistry::get(\Class::class, 'rand')
            : \rand($min, $max);
    }
    
  3. Test Isolation: Forgetting MockRegistry::reset() causes bleeding mocks between tests. Use:

    MockRegistry::reset(); // Clears all overrides
    
  4. Namespace Collisions: Overriding functions in the same namespace as your overrides (e.g., \PHPAutoloadOverride) may cause conflicts. Use explicit namespaces:

    Override::apply($classLoader, [
        'App\' => ['time' => 'App\Testing\Overrides']
    ]);
    

Debugging Tips

  • Verify Overrides: Check if overrides are applied by inspecting the modified class source (use var_dump(file_get_contents()) on the loaded file).

  • Logging: Enable debug mode in OverrideFactory:

    OverrideFactory::create()->setDebug(true)->apply($classLoader);
    
  • Coverage Tools: The library preserves coverage reports (tested with Xdebug). Ensure no side effects in CI pipelines.

Extension Points

  1. Custom Override Namespaces: Extend Override::apply() to support custom namespaces:

    Override::apply($classLoader, [
        'App\Services\' => ['log' => 'App\Testing\Mocks']
    ]);
    
  2. Pre/Post-Processing: Hook into the parser via OverrideFactory::getParser() to modify AST nodes before overriding:

    $factory->setParserCallback(function ($parser) {
        $parser->addNodeVisitor(new CustomVisitor());
        return $parser;
    });
    
  3. Performance Optimization: Cache override declarations for repeated test runs:

    static $overrides = null;
    if (null === $overrides) {
        $overrides = OverrideFactory::create()->build();
    }
    Override::apply($classLoader, $overrides);
    
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope