Mutagenesis\Utility\Diff::difference PHP Method

difference() public static method

Returns the diff between two arrays or strings.
public static difference ( array | string $from, array | string $to, integer $contextLines = 3 ) : string
$from array | string
$to array | string
$contextLines integer
return string
    public static function difference($from, $to, $contextLines = 3)
    {
        if (is_string($from)) {
            $from = preg_split('(\\r\\n|\\r|\\n)', $from);
        }
        if (is_string($to)) {
            $to = preg_split('(\\r\\n|\\r|\\n)', $to);
        }
        $buffer = "";
        $start = array();
        $end = array();
        $fromLength = count($from);
        $toLength = count($to);
        $length = min($fromLength, $toLength);
        for ($i = 0; $i < $length; ++$i) {
            if ($from[$i] === $to[$i]) {
                $start[] = $from[$i];
                unset($from[$i], $to[$i]);
            } else {
                break;
            }
        }
        $length -= $i;
        for ($i = 1; $i < $length; ++$i) {
            if ($from[$fromLength - $i] === $to[$toLength - $i]) {
                array_unshift($end, $from[$fromLength - $i]);
                unset($from[$fromLength - $i], $to[$toLength - $i]);
            } else {
                break;
            }
        }
        $common = self::longestCommonSubsequence(array_values($from), array_values($to));
        $diff = array();
        $line = 0;
        foreach ($start as $token) {
            $diff[] = array($token, 0);
        }
        reset($from);
        reset($to);
        foreach ($common as $token) {
            while (($fromToken = reset($from)) !== $token) {
                $diff[] = array(array_shift($from), 2);
            }
            while (($toToken = reset($to)) !== $token) {
                $diff[] = array(array_shift($to), 1);
            }
            $diff[] = array($token, 0);
            array_shift($from);
            array_shift($to);
        }
        while (($token = array_shift($from)) !== NULL) {
            $diff[] = array($token, 2);
        }
        while (($token = array_shift($to)) !== NULL) {
            $diff[] = array($token, 1);
        }
        foreach ($end as $token) {
            $diff[] = array($token, 0);
        }
        $inOld = FALSE;
        $i = 0;
        $old = array();
        foreach ($diff as $line) {
            if ($line[1] === 0) {
                if ($inOld === FALSE) {
                    $inOld = $i;
                }
            } else {
                if ($inOld !== FALSE) {
                    if ($i - $inOld > 5) {
                        $old[$inOld] = $i - 1;
                    }
                    $inOld = FALSE;
                }
            }
            ++$i;
        }
        $start = isset($old[0]) ? $old[0] : 0;
        $end = count($diff);
        $i = 0;
        if ($tmp = array_search($end, $old)) {
            $end = $tmp;
        }
        $newChunk = TRUE;
        $context = array();
        $contextPre = array();
        $contextPost = array();
        $contextPreSet = false;
        for ($i = $start; $i < $end; $i++) {
            if (isset($old[$i])) {
                $buffer .= "\n";
                $newChunk = TRUE;
                $i = $old[$i];
            }
            if ($newChunk) {
                // TODO: Implement chunk range information.
                $buffer .= "@@ @@\n";
                $newChunk = FALSE;
            }
            if ($diff[$i][1] === 1) {
                $buffer .= '+' . $diff[$i][0] . "\n";
            } else {
                if ($diff[$i][1] === 2) {
                    $popc = $contextLines;
                    if (count($context) < $contextLines) {
                        $popc = count($context);
                    }
                    if ($popc > 0) {
                        while ($popc > 0) {
                            $buffer .= array_pop($context);
                            $popc--;
                        }
                    }
                    $context = array();
                    $contextPreSet = true;
                    $buffer .= '-' . $diff[$i][0] . "\n";
                } else {
                    $context[] = ' ' . $diff[$i][0] . "\n";
                    if ($contextPreSet && count($context) == $contextLines) {
                        $buffer .= implode('', $context);
                        $context = array();
                        break;
                    }
                }
            }
        }
        if (count($context) > 0) {
            $buffer .= implode('', $context);
        }
        return $buffer;
    }

Usage Example

 /**
  * Calculate the unified diff between the original source code and its
  * its mutated form
  *
  * @return string
  */
 public function getDiff()
 {
     $original = $this->_reconstructFromTokens($this->_tokensOriginal);
     $mutated = $this->_reconstructFromTokens($this->_tokensMutated);
     $difference = \Mutagenesis\Utility\Diff::difference($original, $mutated);
     return $difference;
 }