wmde / Diff

䷂ Library for diffing, patching and representing differences between objects
BSD 3-Clause "New" or "Revised" License
200 stars 15 forks source link

Diff

Build Status Code Coverage Scrutinizer Quality Score Latest Stable Version Download count

Diff is a small standalone PHP library for representing differences between data structures, computing such differences, and applying them as patches. It is extremely well tested and allows users to define their own comparison strategies.

Diff does not provide any support for computing or representing the differences between unstructured data, ie text.

A full history of the different versions of Diff can be found in the release notes.

Requirements

Diff 3.x:

Diff 2.x:

Installation

To add this package as a local, per-project dependency to your project, simply add a dependency on diff/diff to your project's composer.json file. Here is a minimal example of a composer.json file that just defines a dependency on Diff 3.x:

{
    "require": {
        "diff/diff": "~3.0"
    }
}

High level structure

The Diff library can be subdivided into several components. The main components are:

There are two support components, which are nevertheless package public:

Usage

Representing diffs

A diff consists out of diff operations. These can be atomic operations such as add, change and remove. These can also be diffs themselves, when dealing with nested structures. Hence the composite pattern is used.

Diff operations implement the DiffOp interface.

The available operations are:

These can all be found in src/DiffOp.

The Diff class can be set to be either associative or non-associative. In case of the later, only DiffOpAdd and DiffOpRemove are allowed in it.

Diffing data

To compute the difference between two data structures, an instance of Differ is used. The Differ interface has a single method.

/**
 * Takes two arrays, computes the diff, and returns this diff as an array of DiffOp.
 *
 * @param array $oldValues The first array
 * @param array $newValues The second array
 *
 * @throws Exception
 * @return DiffOp[]
 */
public function doDiff( array $oldValues, array $newValues ): array;

Implementations provided by Diff:

All differ functionality can be found in src/Differ.

Applying patches

To apply a diff as a patch onto a data structure, an instance of Patcher is used. The Patcher interface has a single method.

/**
 * Applies the applicable operations from the provided diff to
 * the provided base value.
 *
 * @param array $base
 * @param Diff $diffOps
 *
 * @return array
 */
public function patch( array $base, Diff $diffOps ): array;

Implementations provided by Diff:

All classes part of the patcher component can be found in src/Patcher

ValueComparer

The ValueComparer interface contains one method:

/**
 * @param mixed $firstValue
 * @param mixed $secondValue
 *
 * @return bool
 */
public function valuesAreEqual( $firstValue, $secondValue ): bool;

Implementations provided by Diff:

All classes part of the ValueComparer component can be found in src/Comparer

ArrayComparer

The ArrayComposer interface contains one method:

/**
 * Returns an array containing all the entries from arrayOne that are not present
 * in arrayTwo.
 *
 * Implementations are allowed to hold quantity into account or to disregard it.
 *
 * @param array $firstArray
 * @param array $secondArray
 *
 * @return array
 */
public function diffArrays( array $firstArray, array $secondArray ): array;

Implementations provided by Diff:

All classes part of the ArrayComparer component can be found in src/ArrayComparer

Examples

Manually constructing a diff

$diff = new Diff( array(
    'email' => new DiffOpAdd( 'nyan@c.at' ),
    'awesome' => new DiffOpChange( 42, 9001 ),
) );

Computing a diff

$oldVersion = array(
    'awesome' => 42,
);

$newVersion = array(
    'email' => 'nyan@c.at',
    'awesome' => 9001,
);

$differ = new MapDiffer();
$diff = $differ->doDiff( $oldVersion, $newVersion );

Applying a diff as patch

$oldVersion = array(
    /* ... */
);

$diff = new Diff( /* ... */ );

$patcher = new MapPatcher();
$newVersion = $patcher->patch( $oldVersion, $diff );

Links