【发布时间】:2013-01-15 09:51:23
【问题描述】:
我需要一个 PHP 函数,它可以断言两个数组相同,同时忽略一组指定键的值(只有值,键必须匹配)。
实际上,数组必须具有相同的结构,但有些值可以忽略。
例如,考虑以下两个数组:
Array
(
[0] => Array
(
[id] => 0
[title] => Book1 Title
[creationDate] => 2013-01-13 17:01:07
[pageCount] => 0
)
)
Array
(
[0] => Array
(
[id] => 1
[title] => Book1 Title
[creationDate] => 2013-01-13 17:01:07
[pageCount] => 0
)
)
如果我们忽略键 id 的值,它们是相同的。
我也想考虑嵌套数组的可能性:
Array
(
[0] => Array
(
[id] => 0
[title] => Book1 Title
[creationDate] => 2013-01-13 17:01:07
[pageCount] => 0
)
[1] => Array
(
[id] => 0
[title] => Book2 Title
[creationDate] => 2013-01-13 18:01:07
[pageCount] => 0
)
)
Array
(
[0] => Array
(
[id] => 2
[title] => Book1 Title
[creationDate] => 2013-01-13 17:01:07
[pageCount] => 0
)
[1] => Array
(
[id] => 3
[title] => Book2 Title
[creationDate] => 2013-01-13 18:01:07
[pageCount] => 0
)
)
因为我需要它进行测试,所以我提出了以下扩展 PHPUnit_Framework_TestCase 并使用其断言函数的类:
class MyTestCase extends PHPUnit_Framework_TestCase
{
public static function assertArraysSame($expected, $actual, array $ignoreKeys = array())
{
self::doAssertArraysSame($expected, $actual, $ignoreKeys, 1);
}
private static function doAssertArraysSame($expected, $actual, array $ignoreKeys = array(), $depth, $maxDepth = 256)
{
self::assertNotEquals($depth, $maxDepth);
$depth++;
foreach ($expected as $key => $exp) {
// check they both have this key
self::assertArrayHasKey($key, $actual);
// check nested arrays
if (is_array($exp))
self::doAssertArraysSame($exp, $actual[$key], $ignoreKeys, $depth);
// check they have the same value unless the key is in the to-ignore list
else if (array_search($key, $ignoreKeys) === false)
self::assertSame($exp, $actual[$key]);
// remove the current elements
unset($expected[$key]);
unset($actual[$key]);
}
// check that the two arrays are both empty now, which means they had the same lenght
self::assertEmpty($expected);
self::assertEmpty($actual);
}
}
doAssertArraysSame 遍历其中一个数组并递归断言这两个数组具有相同的键。它还会检查它们是否具有相同的值,除非当前键在要忽略的键列表中。
为确保两个数组具有完全相同数量的元素,在迭代期间删除每个元素,并且在循环结束时,函数检查两个数组是否为空。
用法:
class MyTest extends MyTestCase
{
public function test_Books()
{
$a1 = array('id' => 1, 'title' => 'the title');
$a2 = array('id' => 2, 'title' => 'the title');
self::assertArraysSame($a1, $a2, array('id'));
}
}
我的问题是:有没有更好或更简单的方法来完成这项任务,也许使用一些已经可用的 PHP/PHPUnit 函数?
编辑:请记住,我不一定需要 PHPUnit 的解决方案,如果有一个普通的 PHP 函数可以做到这一点,我可以在我的测试中使用它。
【问题讨论】:
-
array_diff怎么样?如果返回空数组则表示数组所在的地方相同。 -
@PLB 是的,这可能会有所帮助,但
array_diff只检查 n 维数组的一维,这意味着如果我想的话,无论如何我都必须在递归循环中使用它支持嵌套数组。另外,在我的情况下,如果来自array_diff的结果数组不为空,我将不得不检查该数组的键是否在忽略列表中。 -
你真的在写测试吗?或者你在代码中需要这个?我的意思是,您的问题意味着您“只”需要该功能,但是您不应该使用 testcase/assert 类和功能。您是否检查了 array_diff 手册页上的 cmets?多维示例在某处.. php.net/manual/en/function.array-diff.php
-
@Nanne 我需要它进行测试,但我认为这无关紧要。如果有一个很好的通用函数可以开箱即用,我可以在我的 TestCase 类中使用它,这就是我要求一个函数的原因。这个问题不一定与 PHPUnit 相关。关于
array_diff,请看我之前的评论。手册页中提出的所有多维解决方案都很笨拙、效率低下或仅适用于二维数组。 -
@testing:我同意,我的意思是相反的:如果你不测试,那么使用你正在使用的类会很奇怪:)。最后,比较多个提及的数组将需要某种形式的深度。我不确定您是否可以提高效率。底线是您需要测试(嵌套)数组的所有键/值对。我不确定你是否可以不尴尬。