Как array_keys выполняет поиск значения? - PullRequest
3 голосов
/ 28 декабря 2011

Как PHP array_keys выполняет поиск значения?

Пример:

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

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

Так как они являются ключевыми, пары значений. Я предполагаю, что PHP выполняет поиск на основе хэша, а не перебирает каждую из пар ключей в массиве.

Есть "мысли о ясности" по этому поводу?

Вопрос, вдохновленный этим вопросом: Как получить ключи пустых элементов в массиве, если соответствующий элемент в массиве аналогичного размера является числом (без итерации)?

Ответы [ 3 ]

5 голосов
/ 28 декабря 2011

В источнике 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 голос
/ 28 декабря 2011

Пожалуйста, смотрите определение array_keys , обратите внимание также на комментарии, которые довольно хорошо это объясняют:

Возврат только ключей из входного массива, опционально только для указанного значения поиска

и позже:

Пройдите через массив ввода и добавьте ключи в возвращаемый массив

Определение для PHP 5.3 следующим образом: ext/standard/array.c:

   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 /* }}} */

Выполнение поиска также объясняется на странице справки PHP для array_keys & shy; Документы :

Если указано необязательное search_value, возвращаются только ключи для этого значения. В противном случае возвращаются все ключи ввода.

См. Также параметр $strict, чтобы повлиять на сравнение значений:

Определяет необходимость строгого сравнения (===) при поиске.

Два типа сравнения == (равно) и === (идентично) также задокументированы .

0 голосов
/ 28 декабря 2011

Я подозреваю, что это не так просто:

  • Если вы не зададите последний параметр "strict" как true, PHP может нужно пройти массив, по пути преобразования значений в сопоставимый тип.
  • Если вы ДАЕТЕ для «строгого» значения true, может также понадобиться выполнить итерацию массива, чтобы исключить неправильные типы
...