array_keys如何搜索值?

时间:2011-12-28 17:34:19

标签: php php-internals

PHP array_keys如何搜索值?

示例:

$array2 = array("xyz", "xyz", "abc", "abc", "xyz", "xyz", "text", "abc", "text");

print_r(array_keys($array2,"abc"));
  

因为它们是关键的价值对。我猜PHP是基于哈希进行搜索而不是遍历数组中的每个密钥对。

对此有什么'清晰的想法'?

受此问题启发的问题:How to get the keys of empty elements in an array if the corresponding element in a similar-sized array is a number (without iteration)?

3 个答案:

答案 0 :(得分:5)

在php源代码中,他们逐个遍历每个键和值。 https://github.com/php/php-src/blob/master/ext/standard/array.c#L2439

/* {{{ proto array array_keys(array input [, mixed search_value[, bool strict]])
   Return just the keys from the input array, optionally only for the specified search_value */
PHP_FUNCTION(array_keys)
{
    zval *input,                /* Input array */
         *search_value = NULL,  /* Value to search for */
         **entry,               /* An entry in the input array */
           res,                 /* Result of comparison */
          *new_val;             /* New value */
    int    add_key;             /* Flag to indicate whether a key should be added */
    char  *string_key;          /* String key */
    uint   string_key_len;
    ulong  num_key;             /* Numeric key */
    zend_bool strict = 0;       /* do strict comparison */
    HashPosition pos;
    int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zb", &input, &search_value, &strict) == FAILURE) {
        return;
    }

    if (strict) {
        is_equal_func = is_identical_function;
    }

    /* Initialize return array */
    if (search_value != NULL) {
        array_init(return_value);
    } else {
        array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
    }
    add_key = 1;

    /* Go through input array and add keys to the return array */
    zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
    while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {
        if (search_value != NULL) {
            is_equal_func(&res, search_value, *entry TSRMLS_CC);
            add_key = zval_is_true(&res);
        }

        if (add_key) {
            MAKE_STD_ZVAL(new_val);

            switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 1, &pos)) {
                case HASH_KEY_IS_STRING:
                    ZVAL_STRINGL(new_val, string_key, string_key_len - 1, 0);
                    zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
                    break;

                case HASH_KEY_IS_LONG:
                    Z_TYPE_P(new_val) = IS_LONG;
                    Z_LVAL_P(new_val) = num_key;
                    zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
                    break;
            }
        }

        zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
    }
}
/* }}} */

答案 1 :(得分:1)

请参阅array_keys definition,同时注意解释得非常好的评论:

  

仅返回输入数组中的键,可选地仅返回指定的search_value

以及后来:

  

浏览输入数组并将键添加到返回数组

ext/standard/array.c上的PHP 5.3的定义如下:

   2427 /* {{{ proto array array_keys(array input [, mixed search_value[, bool strict]])
   2428    Return just the keys from the input array, optionally only for the specified search_value */
   2429 PHP_FUNCTION(array_keys)
   2430 {
   2431     zval *input,                /* Input array */
   2432          *search_value = NULL,  /* Value to search for */
   2433          **entry,               /* An entry in the input array */
   2434            res,                 /* Result of comparison */
   2435           *new_val;             /* New value */
   2436     int    add_key;             /* Flag to indicate whether a key should be added */
   2437     char  *string_key;          /* String key */
   2438     uint   string_key_len;
   2439     ulong  num_key;             /* Numeric key */
   2440     zend_bool strict = 0;       /* do strict comparison */
   2441     HashPosition pos;
   2442     int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
   2443 
   2444     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zb", &input, &search_value, &strict) == FAILURE) {
   2445         return;
   2446     }
   2447 
   2448     if (strict) {
   2449         is_equal_func = is_identical_function;
   2450     }
   2451 
   2452     /* Initialize return array */
   2453     if (search_value != NULL) {
   2454         array_init(return_value);
   2455     } else {
   2456         array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
   2457     }
   2458     add_key = 1;
   2459 
   2460     /* Go through input array and add keys to the return array */
   2461     zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
   2462     while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {
   2463         if (search_value != NULL) {
   2464             is_equal_func(&res, search_value, *entry TSRMLS_CC);
   2465             add_key = zval_is_true(&res);
   2466         }
   2467 
   2468         if (add_key) {
   2469             MAKE_STD_ZVAL(new_val);
   2470 
   2471             switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 1, &pos)) {
   2472                 case HASH_KEY_IS_STRING:
   2473                     ZVAL_STRINGL(new_val, string_key, string_key_len - 1, 0);
   2474                     zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
   2475                     break;
   2476 
   2477                 case HASH_KEY_IS_LONG:
   2478                     Z_TYPE_P(new_val) = IS_LONG;
   2479                     Z_LVAL_P(new_val) = num_key;
   2480                     zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);
   2481                     break;
   2482             }
   2483         }
   2484 
   2485         zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
   2486     }
   2487 }
   2488 /* }}} */

array_keys­Docs的PHP手册页上也解释了执行的搜索:

  

如果指定了可选的search_value,则仅返回该值的键。否则,将返回输入中的所有键。

另请参阅$strict参数以影响比较值的方式:

  

确定在搜索过程中是否应使用严格比较(===)。

两种类型的比较==(等于)和===(相同)是documented as well

答案 2 :(得分:0)

我怀疑这并不容易:

  • 如果不将最后一个参数“strict”设为true,PHP可能会 需要走数组,一路上将值转换为a 比较型。
  • 如果你把“strict”作为true,那么也可能需要迭代数组以排除错误的类型