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 Setup

  1. Installation:

    composer require sebastian/diff
    

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

    composer require --dev sebastian/diff
    
  2. First Use Case: Generate a unified diff between two strings:

    use SebastianBergmann\Diff\Differ;
    use SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder;
    
    $differ = new Differ(new StrictUnifiedDiffOutputBuilder);
    echo $differ->diff('original content', 'modified content');
    
  3. Where to Look First:

    • Differ class: Core diff computation.
    • Output builders: StrictUnifiedDiffOutputBuilder (recommended), DiffOnlyOutputBuilder (minimal output).
    • Parser class: For parsing existing diffs (e.g., from Git) into structured objects.

Implementation Patterns

Core Workflows

  1. Generating Diffs:

    • Standard unified diff (Git/patch-compatible):
      $differ = new Differ(new StrictUnifiedDiffOutputBuilder(['header' => '--- Old ---', '--- New ---']));
      $diff = $differ->diff($oldString, $newString);
      
    • Minimal diff (only changed lines):
      $differ = new Differ(new DiffOnlyOutputBuilder);
      $diff = $differ->diff($oldString, $newString);
      
  2. Parsing Diffs:

    • Parse Git diff output into an object graph:
      use SebastianBergmann\Diff\Parser;
      $parser = new Parser;
      $diffObject = $parser->parse($gitDiffString);
      
    • Access structured data (e.g., chunks, lines):
      foreach ($diffObject->getChunks() as $chunk) {
          foreach ($chunk->getLines() as $line) {
              echo $line->getContent(); // Line content
              echo $line->getType();    // 1=added, 2=removed, 3=context
          }
      }
      
  3. Custom Output:

    • Implement DiffOutputBuilderInterface for bespoke formatting:
      class CustomOutputBuilder implements DiffOutputBuilderInterface {
          public function build($diff): string {
              return "Custom: " . $diff->getLinesAsString();
          }
      }
      $differ = new Differ(new CustomOutputBuilder);
      
  4. Integration with Laravel:

    • Logging diffs:
      use Illuminate\Support\Facades\Log;
      Log::debug('Config diff:', ['diff' => $differ->diff(config('old'), config('new'))]);
      
    • Test assertions:
      $this->assertStringContainsString('+added line', $differ->diff($expected, $actual));
      
    • API response validation:
      $responseDiff = $differ->diff($expectedJson, $response->getContent());
      $this->assertEmpty($responseDiff); // Assert no differences
      
  5. Performance-Critical Scenarios:

    • Use StrictUnifiedDiffOutputBuilder with optimized options:
      $builder = new StrictUnifiedDiffOutputBuilder([
          'contextLines' => 3, // Reduce context for large files
          'addLineNumbers' => false,
      ]);
      

Gotchas and Tips

Pitfalls

  1. Breaking Changes in v9.0.0:

    • UnifiedDiffOutputBuilder and AbstractChunkOutputBuilder were removed. Use StrictUnifiedDiffOutputBuilder instead.
    • Legacy LongestCommonSubsequenceCalculator interface and $lcs parameter are deprecated (removed in v9.0.0). No replacement needed—Myers' algorithm is now the default.
  2. Line Number Offsets:

    • Chunks with getStartRange() === 0 or getEndRange() === 0 use 1-based indexing after insertion/deletion. Example:
      $chunk->getStart(); // Returns line *after* which to insert (not the first line of the chunk).
      
  3. Empty Diffs:

    • UnifiedDiffOutputBuilder returns an empty string if no differences exist (previously returned headers). Handle this in assertions:
      $diff = $differ->diff($a, $b);
      $this->assertEmpty($diff); // Fails if headers are expected.
      
  4. Newline Warnings:

    • emitNoLineEndEofWarning (default: true) adds \ No newline at end of file warnings. Disable for test comparisons:
      $builder = new StrictUnifiedDiffOutputBuilder(['emitNoLineEndEofWarning' => false]);
      
  5. PHP 8.3+ Compatibility:

    • Dropped support for PHP 8.3 in v8.0.0. Ensure your project uses PHP 8.2 or lower if relying on older versions.

Debugging Tips

  1. Inspect Diff Objects:

    • Use print_r($parser->parse($diffString)) to debug parsed diffs. Key properties:
      • Diff::getChunks(): Array of Chunk objects.
      • Chunk::getLines(): Array of Line objects with type (1=added, 2=removed, 3=context) and content.
  2. Handle Binary Data:

    • The package assumes textual diffs. For binary data (e.g., images), use a library like spatie/array-to-xml or base64-encode first.
  3. Custom Formatting Quirks:

    • If implementing DiffOutputBuilderInterface, ensure your build() method handles:
      • Empty diffs (return "").
      • Malformed input (validate $diff object structure).
  4. Performance Tuning:

    • For large files, reduce contextLines in StrictUnifiedDiffOutputBuilder:
      $builder = new StrictUnifiedDiffOutputBuilder(['contextLines' => 1]);
      
    • Myers' algorithm (v9.0.0+) is memory-efficient but may still struggle with >100KB files. Pre-process data (e.g., chunk by sections).
  5. Laravel-Specific:

    • Avoid global state: Instantiate Differ and Parser per request/artisan command to prevent memory leaks.
    • Cache diffs: For repeated comparisons (e.g., config validation), cache results:
      $diffCache = Cache::remember("diff_{$key}", now()->addHours(1), function () use ($old, $new) {
          return $differ->diff($old, $new);
      });
      

Extension Points

  1. Custom Diff Algorithms:

    • Extend Differ by injecting a custom DiffAlgorithm (internal interface). Example:
      class CustomAlgorithm implements \SebastianBergmann\Diff\DiffAlgorithm {
          public function compute($expected, $actual): \SebastianBergmann\Diff\Diff {
              // Implement custom logic (e.g., semantic diff for JSON).
          }
      }
      $differ = new Differ(new CustomAlgorithm(), new StrictUnifiedDiffOutputBuilder);
      
  2. Output Builder Extensions:

    • Subclass StrictUnifiedDiffOutputBuilder to modify behavior:
      class ColoredDiffOutputBuilder extends StrictUnifiedDiffOutputBuilder {
          protected function writeLine(string $line, int $type): void {
              $color = $type === 1 ? "\033[32m" : "\033[31m"; // Green/red
              echo $color . $line . "\033[0m";
          }
      }
      
  3. Parser Extensions:

    • Override Parser to handle custom diff formats:
      class CustomParser extends Parser {
          protected function parseChunk(string $chunk): \SebastianBergmann\Diff\Chunk {
              // Custom parsing logic.
          }
      }
      
  4. Laravel Service Provider:

    • Bind the package to the container for dependency injection:
      // config/app.php
      'aliases' => [
          'Diff' => SebastianBergmann\Diff\Facades\Diff::class,
      ],
      
      // app/Providers/AppServiceProvider.php
      public function register() {
          $this->app->singleton(Differ::class, function () {
              return new Differ(new StrictUnifiedDiffOutputBuilder);
          });
      }
      
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