差异实现

6.0.2 2024-07-03 04:53 UTC

README

Latest Stable Version CI Status codecov

sebastian/diff

PHP的差异实现,从PHPUnit中独立出来成为一个组件。

安装

您可以使用Composer将此库添加到项目的本地依赖中

composer require sebastian/diff

如果您只在开发期间需要此库,例如运行项目的测试套件,那么您应该将其添加为开发时间依赖项

composer require --dev sebastian/diff

用法

生成差异

Differ 类可以用于生成两个字符串之间差异的文本表示

<?php declare(strict_types=1);
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;

$differ = new Differ(new UnifiedDiffOutputBuilder);

print $differ->diff('foo', 'bar');

上面的代码生成以下输出

--- Original
+++ New
@@ @@
-foo
+bar

上面示例中使用的 UnifiedDiffOutputBuilder 生成“统一差异”格式的输出,并被PHPUnit等工具使用。

StrictUnifiedDiffOutputBuilder 生成包含块(hunks)的“严格统一差异”格式输出,类似于 diff -u,并与 patchgit apply 兼容。

DiffOnlyOutputBuilder 生成仅包含不同行的输出。

如果这三个输出构建器都不符合您的使用场景,则可以实现 DiffOutputBuilderInterface 以生成自定义输出。

解析差异

Parser 类可以用于将统一差异解析为对象图

use SebastianBergmann\Diff\Parser;
use SebastianBergmann\Git;

$git = new Git('/usr/local/src/money');

$diff = $git->getDiff(
  '948a1a07768d8edd10dcefa8315c1cbeffb31833',
  'c07a373d2399f3e686234c4f7f088d635eb9641b'
);

$parser = new Parser;

print_r($parser->parse($diff));

上面的代码生成以下输出

Array
(
    [0] => SebastianBergmann\Diff\Diff Object
        (
            [from:SebastianBergmann\Diff\Diff:private] => a/tests/MoneyTest.php
            [to:SebastianBergmann\Diff\Diff:private] => b/tests/MoneyTest.php
            [chunks:SebastianBergmann\Diff\Diff:private] => Array
                (
                    [0] => SebastianBergmann\Diff\Chunk Object
                        (
                            [start:SebastianBergmann\Diff\Chunk:private] => 87
                            [startRange:SebastianBergmann\Diff\Chunk:private] => 7
                            [end:SebastianBergmann\Diff\Chunk:private] => 87
                            [endRange:SebastianBergmann\Diff\Chunk:private] => 7
                            [lines:SebastianBergmann\Diff\Chunk:private] => Array
                                (
                                    [0] => SebastianBergmann\Diff\Line Object
                                        (
                                            [type:SebastianBergmann\Diff\Line:private] => 3
                                            [content:SebastianBergmann\Diff\Line:private] =>      * @covers SebastianBergmann\Money\Money::add
                                        )

                                    [1] => SebastianBergmann\Diff\Line Object
                                        (
                                            [type:SebastianBergmann\Diff\Line:private] => 3
                                            [content:SebastianBergmann\Diff\Line:private] =>      * @covers SebastianBergmann\Money\Money::newMoney
                                        )

                                    [2] => SebastianBergmann\Diff\Line Object
                                        (
                                            [type:SebastianBergmann\Diff\Line:private] => 3
                                            [content:SebastianBergmann\Diff\Line:private] =>      */
                                        )

                                    [3] => SebastianBergmann\Diff\Line Object
                                        (
                                            [type:SebastianBergmann\Diff\Line:private] => 2
                                            [content:SebastianBergmann\Diff\Line:private] =>     public function testAnotherMoneyWithSameCurrencyObjectCanBeAdded()
                                        )

                                    [4] => SebastianBergmann\Diff\Line Object
                                        (
                                            [type:SebastianBergmann\Diff\Line:private] => 1
                                            [content:SebastianBergmann\Diff\Line:private] =>     public function testAnotherMoneyObjectWithSameCurrencyCanBeAdded()
                                        )

                                    [5] => SebastianBergmann\Diff\Line Object
                                        (
                                            [type:SebastianBergmann\Diff\Line:private] => 3
                                            [content:SebastianBergmann\Diff\Line:private] =>     {
                                        )

                                    [6] => SebastianBergmann\Diff\Line Object
                                        (
                                            [type:SebastianBergmann\Diff\Line:private] => 3
                                            [content:SebastianBergmann\Diff\Line:private] =>         $a = new Money(1, new Currency('EUR'));
                                        )

                                    [7] => SebastianBergmann\Diff\Line Object
                                        (
                                            [type:SebastianBergmann\Diff\Line:private] => 3
                                            [content:SebastianBergmann\Diff\Line:private] =>         $b = new Money(2, new Currency('EUR'));
                                        )
                                )
                        )
                )
        )
)

注意:如果块大小为0行,即 getStartRange()getEndRange() 返回0,则 getStart()getEnd() 返回的行数比预期少一行。这是应该在插入或删除块之前或之后插入的行号;在其他所有情况下,它给出替换行范围的第一个行号。