Intereting Posts
PHP Twitter API – Как привлечь несколько твитов пользователей? Функция в single.php не получает правильное значение из настраиваемого поля MySQL LAST_INSERT_ID () и FOUND_ROWS () Предупреждение: Division by Zero Работа с PHP и MySQL Как написать рекурсивное регулярное выражение, которое соответствует вложенным круглым скобкам? php-страница в img src Конвертировать необычный формат даты в метку времени наиболее эффективным способом? file_get_contents («php: // input») или $ HTTP_RAW_POST_DATA, какой из них лучше получить тело запроса JSON? Magento: Как проверить, зарегистрирован ли администратор в контроллере модуля? Двустороннее шифрование БД безопасно даже от администратора Хеширование паролей, совместимое с Java и PHP Изменение адреса `from` при отправке электронной почты через GMail Модель Laravel с POINT / POLYGON и т. Д., Используя DB :: raw выражения Возврат первых элементов x из массива Как документировать переменное количество параметров

Почему array_key_exists 1000x медленнее, чем isset на ссылочных массивах?

Я обнаружил, что array_key_exists более 1000 раз медленнее, чем isset при проверке, установлен ли ключ в ссылке массива. Кто-нибудь, кто понимает, как реализуется PHP, объясняет, почему это так?

EDIT: Я добавил еще одно дело, которое, как представляется, указывает на то, что это накладные расходы, необходимые для вызова функций со ссылкой.

Пример бенчмарка

 function isset_( $key, array $array ) { return isset( $array[$key] ); } $my_array = array(); $start = microtime( TRUE ); for( $i = 1; $i < 10000; $i++ ) { array_key_exists( $i, $my_array ); $my_array[$i] = 0; } $stop = microtime( TRUE ); print "array_key_exists( \$my_array ) ".($stop-$start).PHP_EOL; unset( $my_array, $my_array_ref, $start, $stop, $i ); $my_array = array(); $start = microtime( TRUE ); for( $i = 1; $i < 10000; $i++ ) { isset( $my_array[$i] ); $my_array[$i] = 0; } $stop = microtime( TRUE ); print "isset( \$my_array ) ".($stop-$start).PHP_EOL; unset( $my_array, $my_array_ref, $start, $stop, $i ); $my_array = array(); $start = microtime( TRUE ); for( $i = 1; $i < 10000; $i++ ) { isset_( $i, $my_array ); $my_array[$i] = 0; } $stop = microtime( TRUE ); print "isset_( \$my_array ) ".($stop-$start).PHP_EOL; unset( $my_array, $my_array_ref, $start, $stop, $i ); $my_array = array(); $my_array_ref = &$my_array; $start = microtime( TRUE ); for( $i = 1; $i < 10000; $i++ ) { array_key_exists( $i, $my_array_ref ); $my_array_ref[$i] = 0; } $stop = microtime( TRUE ); print "array_key_exists( \$my_array_ref ) ".($stop-$start).PHP_EOL; unset( $my_array, $my_array_ref, $start, $stop, $i ); $my_array = array(); $my_array_ref = &$my_array; $start = microtime( TRUE ); for( $i = 1; $i < 10000; $i++ ) { isset( $my_array_ref[$i] ); $my_array_ref[$i] = 0; } $stop = microtime( TRUE ); print "isset( \$my_array_ref ) ".($stop-$start).PHP_EOL; unset( $my_array, $my_array_ref, $start, $stop, $i ); $my_array = array(); $my_array_ref = &$my_array; $start = microtime( TRUE ); for( $i = 1; $i < 10000; $i++ ) { isset_( $i, $my_array_ref ); $my_array_ref[$i] = 0; } $stop = microtime( TRUE ); print "isset_( \$my_array_ref ) ".($stop-$start).PHP_EOL; unset( $my_array, $my_array_ref, $start, $stop, $i ); 

Вывод

 array_key_exists( $my_array ) 0.0056459903717 isset( $my_array ) 0.00234198570251 isset_( $my_array ) 0.00539588928223 array_key_exists( $my_array_ref ) 3.64232587814 // <~ what on earth? isset( $my_array_ref ) 0.00222992897034 isset_( $my_array_ref ) 4.12856411934 // <~ what on earth? 

Я на PHP 5.3.6.

Пример Codepad .

Related of "Почему array_key_exists 1000x медленнее, чем isset на ссылочных массивах?"

На работе у меня есть экземпляр VM PHP, который включает расширение PECL под названием VLD. Это позволяет вам выполнять PHP-код из командной строки и вместо этого выполнять его, вместо этого он генерирует сгенерированный код операции.

Это блестяще ответить на такие вопросы.

http://pecl.php.net/package/vld

На всякий случай вы идете по этому маршруту (и если вам вообще интересно, как работает PHP внутри, я думаю, вам стоит), вы должны обязательно установить его на виртуальную машину (то есть я бы не установил ее на машине i " m пытается разработать или развернуть). И это команда, которую вы будете использовать, чтобы заставить ее петь:

 php -d vld.execute=0 -d vld.active=1 -f foo.php 

Глядя на коды операций, вы расскажете вам более полную историю, однако у меня есть предположение …. Большинство встроенных PHP-модулей делают копию массива / объекта и действуют на эту копию (а не на запись-на-запись либо, немедленная копия). Наиболее широко известный пример этого – foreach (). Когда вы передаете массив в foreach (), PHP фактически создает копию этого массива и выполняет итерацию на копии. Вот почему вы увидите значительное преимущество в производительности, передав массив как ссылку в foreach следующим образом:

foreach ($ someReallyBigArray как $ k => & $ v)

Но это поведение – то, что передается в явной ссылке вроде этого, – уникально для foreach (). Поэтому я был бы очень удивлен, если бы он сделал array_key_exists () проверкой быстрее.

Хорошо, к тому, что я получаю ..

Большинство встроенных модулей берут копию массива и действуют на эту копию. Я собираюсь начать совершенно безоговорочное предположение, что isset () сильно оптимизирован и что одна из этих оптимизаций, возможно, не делает немедленную копию массива при его передаче.

Я попытаюсь ответить на любые другие вопросы, которые у вас могут возникнуть, но вы, вероятно, могли бы прочитать много из вас в google для «zval_struct» (которая представляет собой структуру данных внутри внутренних структур PHP, в которой хранится каждая переменная. ассоциативный массив), который имеет такие ключи, как «value», «type», «refcount».

Вот источник функции array_key_exists для 5.2.17. Вы можете видеть, что даже если ключ имеет значение null, PHP пытается вычислить хэш. Хотя интересно, что если вы удалите

 // $my_array_ref[$i] = NULL; 

то он работает лучше. Должно существовать несколько запросов хеширования.

 /* {{{ proto bool array_key_exists(mixed key, array search) Checks if the given key or index exists in the array */ PHP_FUNCTION(array_key_exists) { zval **key, /* key to check for */ **array; /* array to check in */ if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &key, &array) == FAILURE) { WRONG_PARAM_COUNT; } if (Z_TYPE_PP(array) != IS_ARRAY && Z_TYPE_PP(array) != IS_OBJECT) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument should be either an array or an object"); RETURN_FALSE; } switch (Z_TYPE_PP(key)) { case IS_STRING: if (zend_symtable_exists(HASH_OF(*array), Z_STRVAL_PP(key), Z_STRLEN_PP(key)+1)) { RETURN_TRUE; } RETURN_FALSE; case IS_LONG: if (zend_hash_index_exists(HASH_OF(*array), Z_LVAL_PP(key))) { RETURN_TRUE; } RETURN_FALSE; case IS_NULL: if (zend_hash_exists(HASH_OF(*array), "", 1)) { RETURN_TRUE; } RETURN_FALSE; default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be either a string or an integer"); RETURN_FALSE; } } 

Не array_key_exists, но удаление ссылки (= NULL) вызывает это. Я прокомментировал это из вашего сценария, и это результат:

 array_key_exists( $my_array ) 0.0059430599212646 isset( $my_array ) 0.0027170181274414 array_key_exists( $my_array_ref ) 0.0038740634918213 isset( $my_array_ref ) 0.0025200843811035 

array_key_exists( $my_array_ref ) только удаление из части array_key_exists( $my_array_ref ) , это модифицированная часть для ссылки:

 $my_array = array(); $my_array_ref = &$my_array; $start = microtime( TRUE ); for( $i = 1; $i < 10000; $i++ ) { array_key_exists( $i, $my_array_ref ); // $my_array_ref[$i] = NULL; } $stop = microtime( TRUE ); print "array_key_exists( \$my_array_ref ) ".($stop-$start).PHP_EOL; unset( $my_array, $my_array_ref, $start, $stop, $i );