【问题标题】:How does array_keys do the search for value?array_keys 如何进行值搜索?
【发布时间】:2012-01-29 08:40:50
【问题描述】:

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)?

【问题讨论】:

  • 当所有的哈希都需要返回时,PHP为什么要根据哈希进行搜索?这就是我不理解你的问题的重点。
  • 在指定$search_value 时,我正在查看array_keys。
  • 当然,但是由于该功能已记录在案(并且从逻辑上讲),它首先需要获取所有键,因此可以选择执行搜索。因此,只有在您拥有所有键之后,您才能搜索一个值。那么在这里搜索哈希有什么帮助呢? - 哈希已经被获取。
  • 我不知道。而且我对符号表也不清楚。因此,由于我缺乏知识和困惑,我的问题可能如雨后春笋般涌现。

标签: php php-internals


【解决方案1】:

请看array_keys definition,还请注意解释得很好的cmets:

仅返回输入数组中的键,可选择仅返回指定的 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】:

    在 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);
        }
    }
    /* }}} */
    

    【讨论】:

    • 哦,好的。所以你的意思是说它必须在 O(n) 中发生?我猜这是因为创建的每个值都必须有自己的 zval?
    • 没有更好的方法来说明 PHP 是如何做到的:D
    • 它的 O(n)。原因更多是因为它们在内部使用的数据结构,它们不维护哪些值映射到哪些键的列表。因此,您只需要迭代所有值。
    • 我是这么认为的。 & 不,优化数组中的重复值。
    • 如果你有兴趣,这里有他们使用的数据结构的描述here
    【解决方案3】:

    我怀疑这并不容易:

    • 如果您没有将最后一个参数“strict”设置为 true,PHP 可能 需要遍历数组,一路将值转换为 可比较的类型。
    • 如果您将“严格”设为 true,则可能还需要迭代数组以排除错误类型

    【讨论】:

      猜你喜欢
      • 2019-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多