问题
Some of my PHPUnit tests call the Facebook "php-business-sdk" so that I can be confident that Facebook's API is continuing to operate as I expect. E.g. getInsights()
within FacebookAds\Object\Ad
.
And those PHPUnit tests have been using assertEqualsCanonicalizing
.
However, the tests are still brittle; Facebook's API often changes not just the order of the top-level array in the result (an array of associative arrays) but also the order of the keys inside the associative arrays.
So what I really need is a version of assertEqualsCanonicalizing
that is recursive and agnostic to the sorting of the keys of the associative arrays within that top-level array too.
I'd rather not code my own if such a function already exists (maybe in PHP, PHPUnit, Laravel, or elsewhere). Does it?
P.S. Here is a simplified example of a result:
[
{
"Spend": "$3,009",
"Campaign ID": 3335626793661,
"Reach": 37640,
"Unique Inline Link Clicks": 2368
},
{
"Spend": "$1,030",
"Campaign ID": 3335626793662,
"Reach": 1620,
"Unique Inline Link Clicks": 231
}
]
(Imagine next time the API returns the same data but with "Reach" being written before "Spend", and the order of the objects can change too.)
P.S. This is not a duplicate of the linked question because I'm specifically asking how to be agnostic of the sorting order of the inner array keys.
回答1:
There isn't a native method for in_array which works recursively.
But many people have solved this issue with a helper like this one:
private function in_array_recursive($needle, $haystack, $strict = true)
{
foreach ($haystack as $value) {
if (($strict ? $value === $needle : $value == $needle) || (is_array($value) && $this->in_array_recursive($needle, $value, $strict))) {
return true;
}
}
return false;
}
回答2:
Until someone shows an existing native function or something better than this, this is what seems to work for my purposes:
/**
* @see https://stackoverflow.com/q/57008999/470749
*
* @param array $expected
* @param array $actual
*/
public function assertEqualsCanonicalizingInner($expected, $actual) {
try {
$this->assertEqualsCanonicalizing(AT::sortInnerArrays($expected), AT::sortInnerArrays($actual));
} catch (\Exception $e) {
$expectedSortedJson = json_encode(AT::sortInnerArrays($expected));
$actualSortedJson = json_encode(AT::sortInnerArrays($actual));
$this->assertTrue(false, __FUNCTION__ . ' failed: ' . PHP_EOL . $expectedSortedJson . PHP_EOL . ' vs ' . PHP_EOL . $actualSortedJson);
}
}
/**
* @see https://stackoverflow.com/q/57008999/470749
*
* @param array $arr
* @return array
*/
public static function sortInnerArrays($arr) {
$resultingOuterArr = [];
foreach ($arr as $k => $v) {
if (is_array($v)) {
foreach ($v as $kInner => $vInner) {
if (is_array($vInner)) {
$v[$kInner] = self::sortInnerArrays($vInner);
}
}
ksort($v);
}
$resultingOuterArr[$k] = $v;
}
sort($resultingOuterArr);
return $resultingOuterArr;
}
来源:https://stackoverflow.com/questions/57008999/does-php-or-phpunit-or-laravel-have-a-function-for-recursive-array-comparison