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 unified/strict unified diffs or diff-only output between strings via Differ and output builders, or parse unified diff text into an object graph with Parser for further processing.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require sebastian/diff
    

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

    composer require --dev sebastian/diff
    
  2. First Use Case: Generate a diff between two strings in a Laravel test or command:

    use SebastianBergmann\Diff\Differ;
    use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
    
    $differ = new Differ(new UnifiedDiffOutputBuilder);
    $diff = $differ->diff('Expected output', 'Actual output');
    
  3. Where to Look First:

    • Differ class: Core diff generation.
    • Output builders: UnifiedDiffOutputBuilder, StrictUnifiedDiffOutputBuilder, or DiffOnlyOutputBuilder for different formats.
    • Parser class: For parsing diff strings into structured objects (useful for Git diffs or custom diff processing).

Implementation Patterns

Core Workflows

1. Generating Diffs in Tests

Replace generic assertion failures with human-readable diffs in Laravel’s phpunit or pestphp:

use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;

public function testStringComparison()
{
    $expected = "Hello, world!";
    $actual = "Hello, Laravel!";

    $differ = new Differ(new UnifiedDiffOutputBuilder);
    $diff = $differ->diff($expected, $actual);

    $this->fail("Strings differ:\n{$diff}");
}

2. Customizing Diff Output

Adjust context lines (new in v8.1.0) for readability:

use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;

$builder = new UnifiedDiffOutputBuilder(3); // 3 lines of context
$differ = new Differ($builder);

Create a custom output builder for JSON diffs:

use SebastianBergmann\Diff\DiffOutputBuilderInterface;
use SebastianBergmann\Diff\Line;

class JsonDiffOutputBuilder implements DiffOutputBuilderInterface
{
    public function build(array $diffs): string
    {
        return json_encode(array_map(function ($diff) {
            return [
                'from' => $diff->getFrom(),
                'to' => $diff->getTo(),
                'chunks' => array_map(function ($chunk) {
                    return [
                        'start' => $chunk->getStart(),
                        'lines' => array_map(function ($line) {
                            return [
                                'type' => $line->getType(),
                                'content' => $line->getContent(),
                            ];
                        }, $chunk->getLines()),
                    ];
                }, $diff->getChunks()),
            ];
        }, $diffs));
    }
}

3. Parsing Git Diffs

Integrate with Git for version control workflows:

use SebastianBergmann\Diff\Parser;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;

$parser = new Parser();
$process = new Process(['git', 'diff', 'HEAD~1', 'HEAD']);
$process->run();

if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}

$diffObject = $parser->parse($process->getOutput());

4. Logging and Debugging

Use diffs in Laravel’s Log facade or laravel-debugbar:

use Illuminate\Support\Facades\Log;
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\DiffOnlyOutputBuilder;

$differ = new Differ(new DiffOnlyOutputBuilder);
$diff = $differ->diff($expectedConfig, $actualConfig);
Log::error("Configuration mismatch:\n{$diff}");

5. Integration with Laravel Testing

Extend phpunit or pestphp assertions:

// In a custom assertion helper (e.g., `app/Helpers/DiffHelper.php`)
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;

function assertDiff($expected, $actual, $message = '')
{
    $differ = new Differ(new UnifiedDiffOutputBuilder);
    $diff = $differ->diff($expected, $actual);
    $this->fail("{$message}\nDiff:\n{$diff}");
}

Integration Tips

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

    // In a service provider (e.g., `AppServiceProvider`)
    $this->app->singleton(Differ::class, function ($app) {
        return new Differ(new UnifiedDiffOutputBuilder);
    });
    
  2. Use in Artisan Commands: Generate diffs for CLI tools:

    use Illuminate\Console\Command;
    use SebastianBergmann\Diff\Differ;
    use SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder;
    
    class CompareCommand extends Command
    {
        protected $signature = 'diff:compare {file1} {file2}';
        protected $description = 'Compare two files and show the diff';
    
        public function handle(Differ $differ)
        {
            $file1 = file_get_contents($this->argument('file1'));
            $file2 = file_get_contents($this->argument('file2'));
            $diff = $differ->diff($file1, $file2);
            $this->output->write($diff);
        }
    }
    
  3. Combine with Laravel Filesystem: Diff file contents dynamically:

    use Illuminate\Support\Facades\Storage;
    use SebastianBergmann\Diff\Differ;
    
    $file1 = Storage::disk('local')->get('file1.txt');
    $file2 = Storage::disk('local')->get('file2.txt');
    $diff = app(Differ::class)->diff($file1, $file2);
    
  4. Extend for Custom Use Cases:

    • Database diffs: Compare query results or migrations.
    • API response diffs: Validate API contracts in tests.
    • Markdown/HTML diffs: Useful for CMS or documentation tools.

Gotchas and Tips

Pitfalls

  1. PHP Version Compatibility:

    • PHP 8.3+ required (as of v8.0.0). Avoid using this package if constrained to older PHP versions.
    • Check your Laravel version: Ensure compatibility (e.g., Laravel 10+ typically uses PHP 8.2+).
  2. Line Endings:

    • Diffs are sensitive to line endings (e.g., \n vs. \r\n). Normalize strings before comparing:
      $string1 = str_replace(["\r\n", "\r"], "\n", $string1);
      $string2 = str_replace(["\r\n", "\r"], "\n", $string2);
      
  3. Large Files:

    • Performance may degrade with very large files (e.g., >1MB). For such cases:
      • Use DiffOnlyOutputBuilder to reduce output size.
      • Process files in chunks or use a streaming approach.
  4. Zero-Length Chunks:

    • If getStartRange() or getEndRange() returns 0, the line numbers are offset by 1. Account for this in custom parsers:
      $startLine = $chunk->getStart() - 1; // Adjust for zero-length chunks
      
  5. Whitespace Sensitivity:

    • The diff is whitespace-sensitive by default. Use trim() or regex to ignore whitespace if needed:
      $normalizedString1 = preg_replace('/\s+/', ' ', $string1);
      $normalizedString2 = preg_replace('/\s+/', ' ', $string2);
      
  6. Output Builder Quirks:

    • StrictUnifiedDiffOutputBuilder is more strict than UnifiedDiffOutputBuilder and may produce different output for edge cases (e.g., empty files).
    • DiffOnlyOutputBuilder omits context lines entirely, which may make diffs harder to read for large changes.

Debugging Tips

  1. Inspect Diff Objects: Use print_r or var_dump to debug parsed diffs:

    $parser = new Parser();
    $diffObject = $parser->parse($diffString);
    print_r($diffObject);
    
  2. Log Raw Diffs: Log the raw diff string before processing to verify input:

    Log::debug("Raw diff input:\n{$diffString}");
    
  3. Handle Encoding Issues: Ensure strings are in the same encoding (e.g., UTF-8) before diffing:

    $string1 = mb_convert_encoding
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4