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

Diff Laravel Package

sebastian/diff

Standalone PHP diff library extracted from PHPUnit. Generate textual diffs between strings with configurable output builders (unified, strict unified, diff-only) or custom formats, and parse unified diffs into an object model for further processing.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require sebastian/diff:^9.0
    

    For development-only use (e.g., testing):

    composer require --dev sebastian/diff:^9.0
    
  2. First Use Case: Generate a unified diff between two strings in a Laravel controller or service:

    use SebastianBergmann\Diff\Differ;
    use SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder;
    
    $differ = new Differ();
    $diff = $differ->diff('old string', 'new string');
    return response()->json(['diff' => $diff]);
    
  3. Where to Look First:

    • Differ class: Core diff logic (now uses Myers' linear-space algorithm by default).
    • StrictUnifiedDiffOutputBuilder: Replaces UnifiedDiffOutputBuilder and AbstractChunkOutputBuilder.
    • Parser: For parsing existing diffs into structured objects (e.g., for version control tools).

Implementation Patterns

Usage Patterns

  1. Generating Diffs in Tests: Use StrictUnifiedDiffOutputBuilder for PHPUnit-style diffs in custom assertions:

    $differ = new Differ();
    $diff = $differ->diff($expectedJson, $actualJson);
    $this->assertEmpty($diff); // Passes if no differences
    
  2. Custom Output Formatting: Extend DiffOutputBuilderInterface for bespoke formats (e.g., HTML or Markdown):

    use SebastianBergmann\Diff\Output\DiffOutputBuilderInterface;
    
    class CustomDiffOutputBuilder implements DiffOutputBuilderInterface {
        public function build(array $diff): string {
            return "<pre>" . htmlspecialchars(implode("\n", $diff)) . "</pre>";
        }
    }
    
  3. Parsing Git Diffs: Integrate with Git commands to compare file versions:

    use SebastianBergmann\Diff\Parser;
    use Symfony\Component\Process\Process;
    
    $process = new Process(['git', 'diff', 'HEAD~1', 'HEAD']);
    $process->run();
    $parser = new Parser();
    $diff = $parser->parse($process->getOutput());
    
  4. API Response Comparison: Suppress EOF warnings for JSON/XML diffs:

    $outputBuilder = new StrictUnifiedDiffOutputBuilder(
        $differ->diff($expected, $actual),
        false, // addLineNumbers
        false, // emitDiffLineEndWarning
        false  // emitNoLineEndEofWarning (suppresses EOF noise)
    );
    

Workflows

  1. Debugging Workflow: Use DiffOnlyOutputBuilder (if available in future versions) or parse diffs for isolated changes:

    $diffArray = $differ->diffToArray($old, $new);
    foreach ($diffArray as $chunk) {
        if ($chunk->isUnchanged()) continue;
        $this->log->debug($chunk->getLines());
    }
    
  2. CI/CD Pipeline: Parse diffs to validate deployments or migrations:

    $parser = new Parser();
    $diff = $parser->parse(file_get_contents('migration_diff.patch'));
    if ($diff->hasChanges()) {
        throw new \RuntimeException("Unapproved changes detected!");
    }
    
  3. Version Control Hooks: Validate commit messages or diffs pre-push:

    $diff = $differ->diff($oldFile, $newFile);
    if (str_contains($diff, '@@')) {
        // Trigger custom validation logic
    }
    

Integration Tips

  1. Laravel Service Providers: Bind the Differ to the container for dependency injection:

    $this->app->singleton(Differ::class, function ($app) {
        return new Differ();
    });
    
  2. Artisan Commands: Create a custom command for ad-hoc diffs:

    use Illuminate\Console\Command;
    use SebastianBergmann\Diff\Differ;
    
    class DiffCommand extends Command {
        protected $signature = 'diff:compare {path1} {path2}';
        protected $description = 'Compare two files';
    
        public function handle(Differ $differ) {
            $content1 = file_get_contents($this->argument('path1'));
            $content2 = file_get_contents($this->argument('path2'));
            $this->output->write($differ->diff($content1, $content2));
        }
    }
    
  3. Middleware for API Diffs: Log diffs between request/response payloads:

    public function handle($request, Closure $next) {
        $response = $next($request);
        if ($request->is('api/*')) {
            $diff = $this->app->make(Differ::class)
                ->diff($request->getContent(), $response->getContent());
            \Log::debug('API Diff:', ['diff' => $diff]);
        }
        return $response;
    }
    

Gotchas and Tips

Pitfalls

  1. Removed UnifiedDiffOutputBuilder: Replace all instances of UnifiedDiffOutputBuilder with StrictUnifiedDiffOutputBuilder. This is a breaking change in v9.0.0.

  2. Removed LCS Calculator Interface: The $lcs parameter in Differ::diff() and Differ::diffToArray() is no longer supported. The package now uses Myers' linear-space algorithm by default.

  3. Empty Diff Handling: StrictUnifiedDiffOutputBuilder returns an empty string for no differences (no headers). Adjust assertions or output logic if relying on headers:

    // Old (pre-9.0.0):
    $this->assertStringContainsString('--- Original', $diff);
    
    // New (9.0.0+):
    $this->assertEmpty($diff); // For identical inputs
    
  4. Line Number Offsets: Chunks with getStartRange() or getEndRange() returning 0 use 1-based indexing after the chunk. Example:

    $chunk->getStart() === 87 // Refers to line *after* the chunk (insertion point)
    
  5. Strict Mode Quirks: StrictUnifiedDiffOutputBuilder skips diff entries with unknown types silently. Validate input data if using custom diff formats.

Debugging

  1. Parser Debugging: Use print_r() or var_dump() on parsed diff objects to inspect structure:

    $parsedDiff = $parser->parse($diffString);
    print_r($parsedDiff->getChunks()[0]->getLines());
    
  2. Output Builder Issues: If diffs appear malformed, check:

    • Line endings: Ensure input strings use \n (Unix-style).
    • Encoding: Normalize strings to UTF-8 before diffing.
    • Builder options: Verify addLineNumbers, emitDiffLineEndWarning, etc.
  3. Performance: For large diffs (e.g., database dumps), stream output or use diffToArray() to reduce memory usage.

Configuration Quirks

  1. Header Customization: StrictUnifiedDiffOutputBuilder supports a header option for custom headers:

    $outputBuilder = new StrictUnifiedDiffOutputBuilder(
        $differ->diff($old, $new),
        false, // addLineNumbers
        false, // emitDiffLineEndWarning
        false, // emitNoLineEndEofWarning
        "Custom Header: $file1 vs $file2" // header
    );
    
  2. Context Lines: Adjust context lines in StrictUnifiedDiffOutputBuilder for broader/narrower diffs:

    $outputBuilder = new StrictUnifiedDiffOutputBuilder(3); // 3 lines of context
    
  3. PHP Compatibility: Ensure your Laravel app targets PHP 8.1+ for full compatibility with v9.0.0.

Extension Points

  1. Custom Diff Algorithms: Override SebastianBergmann\Diff\Differ to implement custom diff logic (e.g., semantic diffs for code).

  2. Output Formatters: Implement DiffOutputBuilderInterface for formats like:

    • HTML: Highlight changes with <span class="added">/<span class="removed">.
    • Markdown: Use +++/--- syntax for GitHub-flavored diffs.
    • JSON: Serialize diff chunks for API responses.
  3. Integration with Laravel Filesystem: Diff file contents directly from storage:

    use Illuminate\Support\Facades\Storage;
    
    $oldContent = Storage::disk('local')->get('old_file.txt');
    $newContent = Storage::disk('local')->get('new_file.txt');
    $diff = $differ->diff($oldContent, $newContent);
    
  4. Event Listeners: Trigger events on diff changes (e

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.
croct/coding-standard
croct/plug-php
nqxcode/phpmorphy
boundwize/pyrameter
testo/facade
headercat/phpstan-extension-ide-helper
yosymfony/parser-utils
innmind/black-box
babenkoivan/elastic-migrations
babenkoivan/elastic-adapter
develia/commons
dmstr/symfony-system-resources-bundle
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
renatomarinho/laravel-page-speed
develia/geo-bundle
austinheap/laravel-database-encryption
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle