【问题标题】:How does PHP's in_array function work?PHP 的 in_array 函数是如何工作的?
【发布时间】:2016-05-13 11:39:53
【问题描述】:

我不是计算机科学家,也没有很强的算法知识,但今天我开始想知道 PHP 的 in_array 方法是如何在幕后工作的。看起来很简单,循环遍历数组的所有元素并根据给定值检查当前元素。但即使使用更大的阵列,它仍然可以非常快速地工作。怎么样?

<?php
$distros = ["Mint", "Debian", "Ubuntu", "Fedora", "CentOS", "Arch"];
if (in_array("Ubuntu", $distros)) {
    echo "Got Ubuntu";
}

【问题讨论】:

  • 定义“非常快”。一个一个地检查相等的值并不是特别困难......
  • 没有什么特别的魔法,它仍然循环遍历每个条目进行比较,直到找到匹配项(或到达数组的末尾),这意味着它是 O(n) 并且“进一步向下" 在数组中找到任何匹配项,需要的时间越长;或者没有任何匹配的数组越长,则需要的时间越长
  • 这样的事情确实强调了大O符号所代表的“最坏情况”。平均情况为 n/2,最佳情况为 1。如果您想测试 in_array 的速度,您要查找的内容不得出现在数组中以获得最坏情况的测量值。
  • 我想加分!与通过代码中的循环手动执行相比,使用 PHP 的 in_array() 可以提供更快的结果。由于PHP 内部所有库函数都在 C++ 或更低级别的语言上运行。

标签: php arrays


【解决方案1】:

这里是:

/* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
 * 0 = return boolean
 * 1 = return key
 */
static inline void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
{
    zval *value,                /* value to check for */
         *array,                /* array to check in */
         *entry;                /* pointer to array entry */
    zend_ulong num_idx;
    zend_string *str_idx;
    zend_bool strict = 0;       /* strict comparison or not */

#ifndef FAST_ZPP
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "za|b", &value, &array, &strict) == FAILURE) {
        return;
    }
#else
    ZEND_PARSE_PARAMETERS_START(2, 3)
        Z_PARAM_ZVAL(value)
        Z_PARAM_ARRAY(array)
        Z_PARAM_OPTIONAL
        Z_PARAM_BOOL(strict)
    ZEND_PARSE_PARAMETERS_END();
#endif

    if (strict) {
        ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
            ZVAL_DEREF(entry);
            if (fast_is_identical_function(value, entry)) {
                if (behavior == 0) {
                    RETURN_TRUE;
                } else {
                    if (str_idx) {
                        RETVAL_STR_COPY(str_idx);
                    } else {
                        RETVAL_LONG(num_idx);
                    }
                    return;
                }
            }
        } ZEND_HASH_FOREACH_END();
    } else {
        ZVAL_DEREF(value);
        if (Z_TYPE_P(value) == IS_LONG) {
            ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
                if (fast_equal_check_long(value, entry)) {
                    if (behavior == 0) {
                        RETURN_TRUE;
                    } else {
                        if (str_idx) {
                            RETVAL_STR_COPY(str_idx);
                        } else {
                            RETVAL_LONG(num_idx);
                        }
                        return;
                    }
                }
            } ZEND_HASH_FOREACH_END();
        } else if (Z_TYPE_P(value) == IS_STRING) {
            ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
                if (fast_equal_check_string(value, entry)) {
                    if (behavior == 0) {
                        RETURN_TRUE;
                    } else {
                        if (str_idx) {
                            RETVAL_STR_COPY(str_idx);
                        } else {
                            RETVAL_LONG(num_idx);
                        }
                        return;
                    }
                }
            } ZEND_HASH_FOREACH_END();
        } else {
            ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
                if (fast_equal_check_function(value, entry)) {
                    if (behavior == 0) {
                        RETURN_TRUE;
                    } else {
                        if (str_idx) {
                            RETVAL_STR_COPY(str_idx);
                        } else {
                            RETVAL_LONG(num_idx);
                        }
                        return;
                    }
                }
            } ZEND_HASH_FOREACH_END();
        }
    }

    RETURN_FALSE;
}
/* }}} */

/* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
   Checks if the given value exists in the array */
PHP_FUNCTION(in_array)
{
    php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}

【讨论】:

  • 我通常不会投反对票,但我必须投反对票……即使我忽略了缺乏任何评论或解释,这也只显示了函数的 C 定义,并没有说明如何它有效,因为定义使用ZEND_HASH_FOREACH_KEY_VAL 进行迭代?地狱不应该被接受。我们真的不知道这个函数在内部是如何工作的......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多