对于一个非常小的数组,
$array === (array) $array
比
is_array($array)
快得多。快了7倍以上。但每次调用只需要大约
1.0 x 10 ^ -6
秒(
0.000001秒
)。所以,除非你要调用它成千上万次,否则不值得这样做。如果你确实需要调用成千上万次,那么我建议你重新考虑你的代码逻辑...
当处理大型数组时,差异就会显现出来。因为
$array === (array) $array
需要复制一个新变量,并且需要在内部迭代比较数组,所以对于大型数组来说,它会慢得多。例如,在一个包含100个整数元素的数组中,
is_array($array)
和小型数组的误差范围相同(
< 2%
),在10000次迭代中运行时间为
0.0909
秒。但是,
$array = (array) $array
的速度非常慢。对于只有100个元素的数组,它已经比
is_array()
慢了两倍以上(运行时间为
0.203
秒)。对于1000个元素,
is_array
的运行时间保持不变,但转换比较的时间增加到
2.0699
秒...
它在小数组中更快的原因是
is_array()
有函数调用的开销,而强制转换操作是一种简单的语言结构...在C代码中迭代小变量通常比函数调用开销更小。但是,对于较大的变量,差异会增加...
这是一个权衡。如果数组足够小,则迭代效率更高。但随着数组大小的增加,它将变得越来越慢(因此函数调用将变得更快)。
另一种看待它的方式是检查每个转换的算法复杂度。
让我们先看一下
is_array()
。它的
source code基本上显示它是一个
O(1)
操作。这意味着它是一个恒定时间操作。但我们还需要看看函数调用。在PHP中,具有单个数组参数的函数调用可以是
O(1)
或
O(n)
,具体取决于是否需要触发写时复制。如果在
$array
是变量引用时调用
is_array($array)
,将触发写时复制并执行变量的完整拷贝。
因此,
is_array()
是最佳情况下的
O(1)
和最坏情况下的
O(n)
。但只要不使用引用,它始终是
O(1)
...
另一方面,类型转换版本执行两个操作。它进行强制类型转换,然后进行相等性检查。因此,让我们分别看一下每个操作。首先,类型转换运算符
handler强制执行输入变量的
a copy。无论它是否是引用。因此,仅使用
(array)
强制转换运算符会导致对数组进行
O(n)
迭代以进行转换(通过copy_ctor调用)。
然后,它将新副本转换为数组。这对于数组和基元来说是
O(1)
的,但对于对象来说是
O(n)
的。
然后执行相同的运算符。
handler 只是一个
is_identical_function()
的代理。现在,如果
$array
不是数组,is_identical 将短路。因此,它的最佳情况为
O(1)
。但是,如果
$array
是一个数组,它可以再次短路,如果哈希表相同(意味着两个变量都是彼此的写入副本)。因此,该情况也是
O(1)
。但请记住,我们在上面强制进行了复制,所以如果它是一个数组,我们不能这样做。因此,由于
zend_hash_compare,它是
O(n)
...
因此,最坏情况下运行时间的结果如下表:
+----------+-------+-----------+-----------+---------------+
| | array | array+ref | non-array | non-array+ref |
+----------+-------+-----------+-----------+---------------+
| is_array | O(1) | O(n) | O(1) | O(n) |
+----------+-------+-----------+-----------+---------------+
| (array) | O(n) | O(n) | O(n) | O(n) |
+----------+-------+-----------+-----------+---------------+
请注意,它们看起来对于引用变量的比例是相同的。但它们并不相同。它们都以
线性方式扩展引用变量。但常数因子会改变。例如,在大小为5的引用数组中,is_array将执行5次内存分配和5次内存复制,然后进行1次类型检查。另一方面,转换版本将执行5次内存分配和5次内存复制,然后进行2次类型检查,接着进行5次类型检查和5次等式检查(
memcmp()
或类似函数)。所以
n=5
对于
is_array
产生11个操作,而对于
===(array)
产生22个操作...
现在,is_array()
确实有一个栈推入的O(1)开销(由于函数调用),但这仅在极小的n
值下占主导地位(我们在上面的基准测试中看到,仅10个数组元素就足以完全消除所有差异)。
结论
我建议选择可读性更好的方法。我认为is_array($array)
比$array === (array) $array
更易读。所以你可以兼得两种方法的优点。
我用于基准测试的脚本:
$elements = 1000;
$iterations = 10000;
$array = array();
for ($i = 0; $i < $elements; $i++) $array[] = $i;
$s = microtime(true);
for ($i = 0; $i < $iterations; $i++) is_array($array);
$e = microtime(true);
echo "is_array completed in " . ($e - $s) ." Seconds\n";
$s = microtime(true);
for ($i = 0; $i < $iterations; $i++) $array === (array) $array;
$e = microtime(true);
echo "Cast completed in " . ($e - $s) ." Seconds\n";
编辑:记录一下,这些结果是在Linux上使用5.3.2得出的...
编辑2:修复了数组速度较慢的原因(由于迭代比较而不是内存原因)。请参见compare_function中的迭代代码...