protected function _compare($type, $expected, $result = null, $trace = null)
{
$compareTypes = function ($expected, $result, $trace) {
$types = array('expected' => gettype($expected), 'result' => gettype($result));
if ($types['expected'] !== $types['result']) {
$expected = trim("({$types['expected']}) " . print_r($expected, true));
$result = trim("({$types['result']}) " . print_r($result, true));
return compact('trace', 'expected', 'result');
}
};
if ($types = $compareTypes($expected, $result, $trace)) {
return $types;
}
$data = array();
if (!is_scalar($expected)) {
foreach ($expected as $key => $value) {
$newTrace = "{$trace}[{$key}]";
$isObject = false;
if (is_object($expected)) {
$isObject = true;
$expected = (array) $expected;
$result = (array) $result;
}
if (!array_key_exists($key, $result)) {
$trace = !$key ? null : $newTrace;
$expected = !$key ? $expected : $value;
$result = $key ? null : $result;
return compact('trace', 'expected', 'result');
}
$check = $result[$key];
if ($isObject) {
$newTrace = $trace ? "{$trace}->{$key}" : $key;
$expected = (object) $expected;
$result = (object) $result;
}
if ($type === 'identical') {
if ($value === $check) {
if ($types = $compareTypes($value, $check, $trace)) {
return $types;
}
continue;
}
if ($check === array()) {
$trace = $newTrace;
return compact('trace', 'expected', 'result');
}
if (is_string($check)) {
$trace = $newTrace;
$expected = $value;
$result = $check;
return compact('trace', 'expected', 'result');
}
} else {
if ($value == $check) {
if ($types = $compareTypes($value, $check, $trace)) {
return $types;
}
continue;
}
if (!is_array($value)) {
$trace = $newTrace;
return compact('trace', 'expected', 'result');
}
}
$compare = $this->_compare($type, $value, $check, $newTrace);
if ($compare !== true) {
$data[] = $compare;
}
}
if (!empty($data)) {
return $data;
}
} elseif (!is_scalar($result)) {
$data = $this->_compare($type, $result, $expected);
if (!empty($data)) {
return array('trace' => $data['trace'], 'expected' => $data['result'], 'result' => $data['expected']);
}
}
if ($type === 'identical' ? $expected === $result : $expected == $result) {
if ($types = $compareTypes($expected, $result, $trace)) {
return $types;
}
return true;
}
return compact('trace', 'expected', 'result');
}