Ну, для тривиально небольшого массива $array === (array) $array
значительно быстрее, чем is_array($array)
.На порядок более чем в 7 раз быстрее.Но каждый звонок только порядка 1.0 x 10 ^ -6
секунд (0.000001 seconds
).Так что, если вы не называете это буквально тысячи раз, это не будет стоить того.И если вы вызываете его тысячи раз, я бы посоветовал вам сделать что-то не так ...
Разница возникает, когда вы работаете с большим массивом.Так как $array === (array) $array
требует, чтобы новая переменная была скопирована, требуется, чтобы массив был внутренне повторен для сравнения, вероятно, он будет ЗНАЧИТЕЛЬНО медленнее для большого массива.Например, в массиве с 100 целочисленными элементами is_array($array)
находится в пределах погрешности (< 2%
) в is_array()
с небольшим массивом (входящий в 0.0909
секунд для 10000 итераций).Но $array = (array) $array
очень медленно.Только для 100 элементов он уже в два раза медленнее, чем is_array()
(входящий в 0.203
секунды).Для 1000 элементов is_array
остался прежним, но сравнение приведений увеличилось до 2.0699
секунд ...
Причина, по которой это быстрее для небольших массивов, заключается в том, что is_array()
имеет издержки, связанные с вызовом функциигде операция приведения представляет собой простую языковую конструкцию ... И итерации по небольшой переменной (в коде C) обычно обходятся дешевле, чем затраты на вызов функции.Но для больших переменных разница увеличивается ...
Это компромисс.Если массив достаточно мал, итерация будет более эффективной.Но по мере увеличения размера массива он будет становиться все медленнее (и, следовательно, вызов функции станет быстрее).
Другой способ взглянуть на него
Другой способ взглянуть на него будетизучить алгоритмическую сложность каждого приведения.
Давайте сначала посмотрим на is_array()
.Это исходный код в основном показывает, что это O(1)
операция.Это означает, что это операция с постоянным временем.Но нам также нужно взглянуть на вызов функции.В PHP вызовы функций с одним параметром массива имеют значение O(1)
или O(n)
в зависимости от того, нужно ли запускать копирование при записи.Если вы вызываете is_array($array)
, когда $array
является ссылкой на переменную, будет выполнено копирование при записи, и произойдет полное копирование переменной.
Таким образом, is_array()
- это лучший случай O(1)
и худший случай O(n)
.Но если вы не используете ссылки, это всегда O(1)
...
В приведенной версии, с другой стороны, выполняется две операции.Он выполняет приведение, затем проверяет равенство.Итак, давайте посмотрим на каждого в отдельности.Оператор приведения обработчик сначала заставляет копию входной переменной.Неважно, если это ссылка или нет.Таким образом, простое использование оператора приведения (array)
вызывает итерацию O(n)
по массиву для его приведения (с помощью вызова copy_ctor).
Затем он преобразует новую копию в массив.Это O(1)
для массивов и примитивов, но O(n)
для объектов.
Затем выполняется идентичный оператор.Обработчик является просто прокси для is_identical_function()
.Теперь is_identical будет закорачиваться, если $array
не является массивом.Поэтому он имеет лучший случай из O(1)
.Но если $array
является массивом, он может снова замкнуть накоротко, если хеш-таблицы идентичны (то есть обе переменные являются копиями друг друга при копировании при записи).Так что этот случай тоже O(1)
.Но помните, что мы принудительно сделали копию выше, поэтому мы не можем сделать это, если это массив.Так что O(n)
благодаря zend_hash_compare ...
Итак, конечный результат - это таблица времени выполнения в худшем случае:
+----------+-------+-----------+-----------+---------------+
| | array | array+ref | non-array | non-array+ref |
+----------+-------+-----------+-----------+---------------+
| is_array | O(1) | O(n) | O(1) | O(n) |
+----------+-------+-----------+-----------+---------------+
| (array) | O(n) | O(n) | O(n) | O(n) |
+----------+-------+-----------+-----------+---------------+
Обратите внимание, что, похоже, они одинаково масштабируются для ссылок. Они не Они оба масштабируются линейно для указанных переменных. Но постоянный фактор меняется. Например, в ссылочном массиве размера 5 is_array выполнит 5 выделений памяти и 5 копий памяти, а затем 1 проверка типа. Версия Cast, с другой стороны, будет выполнять 5 выделений памяти, 5 копий памяти, затем 2 проверки типов, затем 5 проверок типов и 5 проверок на равенство (memcmp()
или тому подобное). Так что n=5
дает 11 операций для is_array
, но 22 операции для ===(array)
...
Теперь у is_array()
есть накладные расходы O (1) при выталкивании стека (из-за вызова функции), но это будет преобладать во время выполнения только для чрезвычайно малых значений n
(мы видели в тесте выше достаточно было всего 10 элементов массива, чтобы полностью устранить все различия).
Итог
Я бы посоветовал перейти на удобочитаемость. Я нахожу is_array($array)
гораздо более читабельным, чем $array === (array) $array
. Таким образом, вы получаете лучшее из обоих миров.
Сценарий, который я использовал для теста:
$elements = 1000;
$iterations = 10000;
$array = array();
for ($i = 0; $i < $elements; $i++) $array[] = $i;
$s = microtime(true);
for ($i = 0; $i < $iterations; $i++) is_array($array);
$e = microtime(true);
echo "is_array completed in " . ($e - $s) ." Seconds\n";
$s = microtime(true);
for ($i = 0; $i < $iterations; $i++) $array === (array) $array;
$e = microtime(true);
echo "Cast completed in " . ($e - $s) ." Seconds\n";
Редактировать: Для записи, эти результаты были с 5.3.2 на Linux ...
Edit2: Исправлена причина, по которой массив работает медленнее (это связано с повторным сравнением, а не с памятью). См. compare_function для кода итерации ...