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
Agents
dg/bypass-finals
claude-code
cursor
testing
phpunit
unit
mocking
finals

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

Install
php artisan boost:add-skill dg/bypass-finals

Save this content to: AGENTS.md

# To My Agents!

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

## Documentation

Any distilled, agent-facing documentation for this package - how it works
internally and the rationale behind key design decisions - lives in `docs/`.
Consult it before non-trivial changes; it is the source of truth from which the
public manual is distilled.

## Project Overview

BypassFinals is a PHP library that removes `final` and `readonly` keywords from source code on-the-fly, enabling mocking of final classes and methods for testing purposes. It works by intercepting PHP's file stream operations and modifying code before it's parsed.

## Key Commands

### Testing
```bash
# Run all tests (composer script runs `tester tests -s`)
composer run tester
# or
vendor/bin/tester tests -s

# Run specific test file
vendor/bin/tester tests/BypassFinals/BypassFinals.phpt -s
```

### Static Analysis
```bash
# Run PHPStan static analysis
composer run phpstan
# or
vendor/bin/phpstan analyse
```

### Development Setup
```bash
# Install dependencies
composer install --dev

# Run tests in different PHP versions (see .github/workflows/tests.yml for supported versions)
# Supports PHP 8.2 through 8.6
```

## Architecture Overview

### Core Components

1. **BypassFinals** (`src/BypassFinals.php`) - Main API class that:
   - Manages configuration (allow/deny paths, cache directory)
   - Registers custom stream wrapper
   - Provides token removal logic
   - Tracks debugging information

2. **MutatingWrapper** (`src/MutatingWrapper.php`) - Stream wrapper that:
   - Intercepts file operations for `.php` files
   - Modifies PHP source code on-the-fly if path is allowed
   - Delegates non-PHP operations to underlying wrapper

3. **NativeWrapper** (`src/NativeWrapper.php`) - Native file operations wrapper that:
   - Implements all PHP stream wrapper methods
   - Temporarily restores native protocol for actual file operations
   - Handles file, directory, and metadata operations

4. **PHPUnitExtension** (`src/PHPUnitExtension.php`) - PHPUnit 10+ integration that:
   - Automatically denies the PHPUnit vendor path (`*/vendor/phpunit/*`)
   - Configures BypassFinals from phpunit.xml parameters (`bypassReadOnly`, `bypassFinal`, `cacheDirectory`, `allowPaths`, `denyPaths`; path masks are semicolon-separated)
   - Enables the library during test bootstrap

5. **bootstrap.php** (`src/bootstrap.php`) - Standalone bootstrap that requires the
   wrapper classes and calls `enable()`. Designed to be loaded *before*
   `vendor/autoload.php` so classes registered in autoload files are also processed.

### How It Works

1. **Stream Wrapper Registration**: Replaces PHP's native `file://` protocol handler with `MutatingWrapper`
2. **File Interception**: When PHP loads a `.php` file, `MutatingWrapper` intercepts the operation
3. **Code Modification**: Uses PHP's tokenizer to remove `final` and `readonly` tokens from source
4. **Caching**: Optional filesystem caching of modified code using SHA1 hashes
5. **Path Filtering**: Allow/deny path rules control which files get modified

### Testing Strategy

- **Nette Tester**: Uses `.phpt` files for comprehensive test coverage
- **Fixtures**: Test files in `tests/BypassFinals/fixtures/` demonstrate actual `final` class removal
- **Stream Operations**: Tests verify that custom stream wrapper doesn't break normal file operations
- **Path Filtering**: Tests ensure allow/deny path rules work correctly
- **Caching**: Tests verify cache functionality with hash-based storage
- **Edge Cases**: Tests handle syntax errors, missing files, and other error conditions

### Configuration Patterns

The library supports multiple configuration approaches:

1. **Direct PHP API** (`enable()` defaults: both `$bypassReadOnly` and `$bypassFinal` are `true`):
   ```php
   DG\BypassFinals::enable();
   DG\BypassFinals::allowPaths(['*/src/*']);
   DG\BypassFinals::setCacheDirectory('/tmp/cache');
   ```

2. **PHPUnit XML Extension** (parameters are optional; omitted boolean params default to `true`):
   ```xml
   <extensions>
       <bootstrap class="DG\BypassFinals\PHPUnitExtension">
           <parameter name="bypassFinal" value="true"/>
           <parameter name="bypassReadOnly" value="false"/>
           <parameter name="cacheDirectory" value="./cache"/>
           <parameter name="allowPaths" value="*/src/*;*/lib/*"/>
           <parameter name="denyPaths" value="*/generated/*"/>
       </bootstrap>
   </extensions>
   ```

3. **Standalone bootstrap** (load before `vendor/autoload.php` to also process autoload-registered classes):
   ```php
   // tests/bootstrap.php
   require __DIR__ . '/../vendor/dg/bypass-finals/src/bootstrap.php';
   require __DIR__ . '/../vendor/autoload.php';
   ```

### Performance Considerations

- **Early Initialization**: Must be enabled before classes are loaded
- **Caching**: Use `setCacheDirectory()` to avoid repeated tokenization
- **Path Filtering**: Use allow/deny paths to limit scope and improve performance
- **Stream Wrapper Overhead**: Minimal overhead for non-PHP files due to delegation

### Debugging

Use `DG\BypassFinals::debugInfo()` to troubleshoot issues. This outputs:
- Configuration status (final/readonly bypass enabled)
- Call stack showing where `enable()` was called
- Classes loaded before BypassFinals was started (these cannot be modified)
- List of files that were successfully modified

### Compatibility

- **PHP Versions**: 8.2 through 8.6 (minimum is now `>=8.2`, per `composer.json`)
- **readonly Support**: enabled by default (the 8.2 minimum guarantees the `T_READONLY` token exists)
- **Testing Frameworks**: PHPUnit, Mockery, Nette Tester
- **Internal Classes**: Cannot modify PHP internal classes like `Closure`

To My Agents!

It is my fervent wish that this file guide every AI coding agent working with code in this repository.

Documentation

Any distilled, agent-facing documentation for this package - how it works internally and the rationale behind key design decisions - lives in docs/. Consult it before non-trivial changes; it is the source of truth from which the public manual is distilled.

Project Overview

BypassFinals is a PHP library that removes final and readonly keywords from source code on-the-fly, enabling mocking of final classes and methods for testing purposes. It works by intercepting PHP's file stream operations and modifying code before it's parsed.

Key Commands

Testing

# Run all tests (composer script runs `tester tests -s`)
composer run tester
# or
vendor/bin/tester tests -s

# Run specific test file
vendor/bin/tester tests/BypassFinals/BypassFinals.phpt -s

Static Analysis

# Run PHPStan static analysis
composer run phpstan
# or
vendor/bin/phpstan analyse

Development Setup

# Install dependencies
composer install --dev

# Run tests in different PHP versions (see .github/workflows/tests.yml for supported versions)
# Supports PHP 8.2 through 8.6

Architecture Overview

Core Components

  1. BypassFinals (src/BypassFinals.php) - Main API class that:

    • Manages configuration (allow/deny paths, cache directory)
    • Registers custom stream wrapper
    • Provides token removal logic
    • Tracks debugging information
  2. MutatingWrapper (src/MutatingWrapper.php) - Stream wrapper that:

    • Intercepts file operations for .php files
    • Modifies PHP source code on-the-fly if path is allowed
    • Delegates non-PHP operations to underlying wrapper
  3. NativeWrapper (src/NativeWrapper.php) - Native file operations wrapper that:

    • Implements all PHP stream wrapper methods
    • Temporarily restores native protocol for actual file operations
    • Handles file, directory, and metadata operations
  4. PHPUnitExtension (src/PHPUnitExtension.php) - PHPUnit 10+ integration that:

    • Automatically denies the PHPUnit vendor path (*/vendor/phpunit/*)
    • Configures BypassFinals from phpunit.xml parameters (bypassReadOnly, bypassFinal, cacheDirectory, allowPaths, denyPaths; path masks are semicolon-separated)
    • Enables the library during test bootstrap
  5. bootstrap.php (src/bootstrap.php) - Standalone bootstrap that requires the wrapper classes and calls enable(). Designed to be loaded before vendor/autoload.php so classes registered in autoload files are also processed.

How It Works

  1. Stream Wrapper Registration: Replaces PHP's native file:// protocol handler with MutatingWrapper
  2. File Interception: When PHP loads a .php file, MutatingWrapper intercepts the operation
  3. Code Modification: Uses PHP's tokenizer to remove final and readonly tokens from source
  4. Caching: Optional filesystem caching of modified code using SHA1 hashes
  5. Path Filtering: Allow/deny path rules control which files get modified

Testing Strategy

  • Nette Tester: Uses .phpt files for comprehensive test coverage
  • Fixtures: Test files in tests/BypassFinals/fixtures/ demonstrate actual final class removal
  • Stream Operations: Tests verify that custom stream wrapper doesn't break normal file operations
  • Path Filtering: Tests ensure allow/deny path rules work correctly
  • Caching: Tests verify cache functionality with hash-based storage
  • Edge Cases: Tests handle syntax errors, missing files, and other error conditions

Configuration Patterns

The library supports multiple configuration approaches:

  1. Direct PHP API (enable() defaults: both $bypassReadOnly and $bypassFinal are true):

    DG\BypassFinals::enable();
    DG\BypassFinals::allowPaths(['*/src/*']);
    DG\BypassFinals::setCacheDirectory('/tmp/cache');
    
  2. PHPUnit XML Extension (parameters are optional; omitted boolean params default to true):

    <extensions>
        <bootstrap class="DG\BypassFinals\PHPUnitExtension">
            <parameter name="bypassFinal" value="true"/>
            <parameter name="bypassReadOnly" value="false"/>
            <parameter name="cacheDirectory" value="./cache"/>
            <parameter name="allowPaths" value="*/src/*;*/lib/*"/>
            <parameter name="denyPaths" value="*/generated/*"/>
        </bootstrap>
    </extensions>
    
  3. Standalone bootstrap (load before vendor/autoload.php to also process autoload-registered classes):

    // tests/bootstrap.php
    require __DIR__ . '/../vendor/dg/bypass-finals/src/bootstrap.php';
    require __DIR__ . '/../vendor/autoload.php';
    

Performance Considerations

  • Early Initialization: Must be enabled before classes are loaded
  • Caching: Use setCacheDirectory() to avoid repeated tokenization
  • Path Filtering: Use allow/deny paths to limit scope and improve performance
  • Stream Wrapper Overhead: Minimal overhead for non-PHP files due to delegation

Debugging

Use DG\BypassFinals::debugInfo() to troubleshoot issues. This outputs:

  • Configuration status (final/readonly bypass enabled)
  • Call stack showing where enable() was called
  • Classes loaded before BypassFinals was started (these cannot be modified)
  • List of files that were successfully modified

Compatibility

  • PHP Versions: 8.2 through 8.6 (minimum is now >=8.2, per composer.json)
  • readonly Support: enabled by default (the 8.2 minimum guarantees the T_READONLY token exists)
  • Testing Frameworks: PHPUnit, Mockery, Nette Tester
  • Internal Classes: Cannot modify PHP internal classes like Closure
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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json