温馨提示:本文翻译自stackoverflow.com,查看原文请点击:php - Why is in_array strict mode on integers slower than non-strict mode?
php php-internals

php - 为什么整数上的in_array严格模式比非严格模式慢?

发布于 2020-03-27 10:38:28

我一直认为in_array严格模式会比非严格模式更快或更慢。但是在一些基准测试之后,我发现在搜索整数时,它们之间的执行时间存在巨大差异。字符串和数组测试表明严格模式更快。为什么?

测试代码-(PHP 7.2.1):

<?php

$array = array_fill(0, 10000, 12345);

for ($i=0; $i<100000; $i++) {
    in_array($i, $array, true);
}

时间php test.php

php -c test.php 12.98s用户0.04s系统98%cpu 13.234


<?php

$array = array_fill(0, 10000, 12345);

for ($i=0; $i<100000; $i++) {
    in_array($i, $array, false);
}

时间php test.php

php -c test.php 6.44s用户0.04s系统99%cpu 6.522

查看更多

查看更多

提问者
Tom
被浏览
229
2019-07-04 00:24

通过跟踪C的C源代码,我可以提供一些小见识in_array

It turns out, when comparing integers, the path to reach the actual equality check for non-strict mode involves fewer operations than strict mode.

Strict mode

In the case where the strict flag to in_array is true, the following occurs:

  1. We call fast_is_identical_function for each element in the array

  2. The fast_is_identical_function first tests that the types of each operand are different (Z_TYPE_P(op1) != Z_TYPE_P(op2)) in hopes of being able to return false early; this is comparison #1.

  3. If the types are the same (they are, in your test case), we then test (Z_TYPE_P(op1) <= IS_TRUE; I've no idea what this does, but it's comparison #2.

  4. After both comparisons have evaluated to false, we jump into zend_is_identical, our first function invocation.

  5. zend_is_identical starts out by again testing Z_TYPE_P(op1) != Z_TYPE_P(op2), another attempt to fail early. This is comparison #3.

  6. If the types are the same, we can descend through the switch (Z_TYPE_P(op1)) statement, comparison #4

  7. Finally we reach the comparison Z_LVAL_P(op1) == Z_LVAL_P(op2) which actually tests the equality of the two values, comparison #5.

In total, to test whether each element of the array is equal to the value we're searching for, there are 5 comparisons and 1 function invocation.

Non-strict mode

By comparison, the non-strict flow for integers specifically (really LONGs) is much simpler, as follows:

  1. Instead of fast_is_identical_function, we instead use fast_equal_check_function for each element in the array.

  2. 该方法fast_equal_check_function开始了将两个值与各种类型转换逻辑进行比较的更为复杂的过程。但是,它的第一个测试确实是针对整数进行了优化,如下所示:

    if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
        if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
            return Z_LVAL_P(op1) == Z_LVAL_P(op2);
    

    我们可以看到...

    1. 立即测试的类型是否op1LONG,它是,则
    2. 立即测试的类型是否op2LONG,它是,则
    3. 立即返回的结果 Z_LVAL_P(op1) == Z_LVAL_P(op2)

对于非严格情况,总共有3个简单相等比较和0个函数调用,而对于严格情况,则至少有 5个比较和1个跳转。

这似乎是一种情况,即尝试进行早期优化会使严格检查的速度比比较两个整数的特定非严格情况的速度慢(通过反复测试操作数的类型,希望我们能更快地找到不等式)。