Проверка на пустые массивы: count vs empty

98

Этот вопрос о том, « Как определить, пуст ли массив PHP », заставил меня задуматься над этим вопросом.

Есть ли причина, которую countследует использовать вместо того, чтобы emptyопределять, пуст массив или нет?

Лично я подумал, что эти 2 эквивалентны для случая пустых массивов, которые вы должны использовать, emptyпотому что это дает логический ответ на логический вопрос. Из приведенного выше вопроса кажется, что count($var) == 0это популярный метод. Для меня, хотя это технически правильно, не имеет смысла. Например, Q: $ var, ты пуст? А: 7 . Хммм ...

Есть ли причина, по которой я должен использовать count == 0вместо этого, или это вопрос личного вкуса?

Как указывали другие в комментариях к теперь удаленному ответу, это countповлияет на производительность для больших массивов, потому что ему придется подсчитывать все элементы, тогда как он emptyможет остановиться, как только он узнает, что он не пуст. Итак, если они дают те же результаты в этом случае, но countпотенциально неэффективны, зачем нам вообще их использовать count($var) == 0?

Дэн МакГрат
источник
Я предполагаю, что вы намерены ограничить диалог исключительно массивами, но, возможно, стоит отметить, что игра полностью меняется, если вы работаете с объектами (например, которые реализуют Countable, Iterator и т. Д.).
9
Пустой массив равен falsePHP - в empty()или нет необходимости count().
Cobby
@Cobby Code, пожалуйста.
TheRealChx101
@ TheRealChx101 как, просто сделать: if (!$myArray) { echo "array is empty"; } sandbox.onlinephpfunctions.com/code/...
коренастый
В настоящее время используется популярный вариант связанного вопроса empty().
PhoneixS 02

Ответы:

97

Я вообще пользуюсь empty. Я не уверен, почему люди действительно используют счетчик - если массив большой, счет занимает больше времени / имеет больше накладных расходов. Если вам просто нужно знать, пуст массив или нет, используйте пустой.

блудница
источник
4
Эти функции действительно различаются, когда массив не пуст.
Jacco
2
@Jacco: Я не спорю с этим. Но если вы тестируете его пустым, я не вижу, какое это имеет значение - это вопрос с логическим результатом, который функция вернет. Что касается того, что считается пустым в, не вижу, как эти критерии дадут неправильный ответ, если только var, которое вы тестируете, не является массивом, и в этом случае это совершенно другая проблема.
prodigitalson
23
@prodigitalson Я бы сказал, что O(1)количество элементов есть , поскольку PHP хранит количество элементов внутри. Посмотрите этот ответ stackoverflow.com/a/5835419/592454
elitalon
4
@eliton: но все же - даже если разница в производительности отсутствует или небольшая, зачем использовать счетчик, если он вам не нужен?
prodigitalson
4
empty () слишком прощает ошибок. Я только что потратил 2 часа на отладку подкласса, который тестировал empty () на частной переменной-члене своего суперкласса (область видимости переменной-члена суперкласса ДОЛЖНА быть защищена, но empty () не возвращал ошибок - результат был просто тем, что должно произошло, не произошло: отсутствие переменной-члена в подклассе рассматривалось точно так же, как если бы эта переменная-член, массив, была пуста - то есть, как если бы она не имела элементов). Это проблематично, и это еще один пример слишком снисходительного PHP.
Мэтью Слайман
47

Мне было любопытно посмотреть, какая из них на самом деле быстрее, поэтому я написал простой скрипт для тестирования этих функций.

<?php

function benchmark($name, $iterations, $action){
    $time=microtime(true);
    for($i=0;$i<=$iterations;++$i){
        $action();
    }
    echo $name . ' ' . round(microtime(true)-$time, 6) . "\n";
}

$iterations = 1000000;
$x = array();
$y = range(0, 10000000);
$actions = array(
    "Empty empty()" => function() use($x){
        empty($x);
    },
    "Empty count()" => function() use($x){
        count($x);
    },
    "Full empty()" => function() use($y){
        empty($y);
    },
    "Full count()" => function() use($y){
        count($y);
    },
    ############
    "IF empty empty()" => function() use($x){
        if(empty($x)){ $t=1; }
    },
    "IF empty count()" => function() use($x){
        if(count($x)){ $t=1; }
    },
    "IF full empty()" => function() use($y){
        if(empty($y)){ $t=1; }
    },
    "IF full count()" => function() use($y){
        if(count($y)){ $t=1; }
    },
    ############
    "OR empty empty()" => function() use($x){
        empty($x) OR $t=1;
    },
    "OR empty count()" => function() use($x){
        count($x) OR $t=1;
    },
    "OR full empty()" => function() use($y){
        empty($y) OR $t=1;
    },
    "OR full count()" => function() use($y){
        count($y) OR $t=1;
    },
    ############
    "IF/ELSE empty empty()" => function() use($x){
        if(empty($x)){ $t=1; } else { $t=2; }
    },
    "IF/ELSE empty count()" => function() use($x){
        if(count($x)){ $t=1; } else { $t=2; }
    },
    "IF/ELSE full empty()" => function() use($y){
        if(empty($y)){ $t=1; } else { $t=2; }
    },
    "IF/ELSE full count()" => function() use($y){
        if(count($y)){ $t=1; } else { $t=2; }
    },
    ############
    "( ? : ) empty empty()" => function() use($x){
        $t = (empty($x) ? 1 : 2);
    },
    "( ? : ) empty count()" => function() use($x){
        $t = (count($x) ? 1 : 2);
    },
    "( ? : ) full empty()" => function() use($y){
        $t = (empty($y) ? 1 : 2);
    },
    "( ? : ) full count()" => function() use($y){
        $t = (count($y) ? 1 : 2);
    }
);

foreach($actions as $name => $action){
    benchmark($name, $iterations, $action);
}
//END

Поскольку я делал это, я также попытался проверить производительность при выполнении операций, которые обычно связаны с count () / empty ()

Используя PHP 5.4.39:

Empty empty() 0.118691
Empty count() 0.218974
Full empty() 0.133747
Full count() 0.216424
IF empty empty() 0.166474
IF empty count() 0.235922
IF full empty() 0.120642
IF full count() 0.248273
OR empty empty() 0.123875
OR empty count() 0.258665
OR full empty() 0.157839
OR full count() 0.224869
IF/ELSE empty empty() 0.167004
IF/ELSE empty count() 0.263351
IF/ELSE full empty() 0.145794
IF/ELSE full count() 0.248425
( ? : ) empty empty() 0.169487
( ? : ) empty count() 0.265701
( ? : ) full empty() 0.149847
( ? : ) full count() 0.252891

Использование HipHop VM 3.6.1 (dbg)

Empty empty() 0.210652
Empty count() 0.212123
Full empty() 0.206016
Full count() 0.204722
IF empty empty() 0.227852
IF empty count() 0.219821
IF full empty() 0.220823
IF full count() 0.221397
OR empty empty() 0.218813
OR empty count() 0.220105
OR full empty() 0.229118
OR full count() 0.221787
IF/ELSE empty empty() 0.221499
IF/ELSE empty count() 0.221274
IF/ELSE full empty() 0.221879
IF/ELSE full count() 0.228737
( ? : ) empty empty() 0.224143
( ? : ) empty count() 0.222459
( ? : ) full empty() 0.221606
( ? : ) full count() 0.231288

Выводы, если вы используете PHP:

  1. empty () намного быстрее, чем count () в обоих сценариях, с пустым и заполненным массивом

  2. count () выполняет то же самое с полным или пустым массивом.

  3. Выполнение простой операции IF или просто логической операции - то же самое.

  4. IF / ELSE немного эффективнее, чем (?:). Если вы не делаете миллиарды итераций с выражениями в середине, это совершенно несущественно.

Выводы, если вы используете HHVM:

  1. empty () немного быстрее, чем count (), но незначительно.

    [Остальное как в PHP]

В заключение, если вам просто нужно знать, пуст ли массив, всегда используйте empty ();

Это был просто любопытный тест, который был проведен без учета многих вещей. Это просто доказательство концепции и может не отражать производственные операции.

Сатаке
источник
Спасибо за образец кода тестирования .... Я просто использовал его и обнаружил, что if($x){он быстрее if(empty($x)){(работает только в том случае, если вы знаете, что $xэто было объявлено).
Redzarf
Ваш тестовый код действительно плохой. Вы добавляете много дополнительных вещей, например, анонимный вызов функции. Если я удаляю и просто запускаю чистый код (для цикла друг за другом), я получаю огромную разницу. И я не имею в виду в этом случае быстрее , если нет countи emptyвызовы в , если заявление. Потом доходит emptyи длится count. Но по сравнению с вашим в голом футляре пустой в десять раз быстрее! Простой тест массива: 0.104662, пустой: 0.177659, count: 1.175125 на PHP 5.6, иначе ваш код дает тот же результат в этой версии, что и вы упомянули. Просто это фальшивые результаты.
golddragon007
16

Думаю, это только личные предпочтения. Некоторые люди могут сказать, что emptyэто быстрее (например, http://jamessocol.com/projects/count_vs_empty.php ), в то время как другие могут сказать, countчто лучше, поскольку изначально он был создан для массивов. emptyявляется более общим и может применяться к другим типам.

Однако php.net дает следующее предупреждение count:

count () может возвращать 0 для переменной, которая не установлена, но также может возвращать 0 для переменной, которая была инициализирована пустым массивом. Используйте isset (), чтобы проверить, установлена ​​ли переменная.

Другими словами, если переменная не установлена, вы получите уведомление от PHP о том, что она не определена. Поэтому перед использованием countбыло бы предпочтительнее проверить переменную с помощью isset. Это не обязательно с empty.

Лоран ле Бо-Мартен
источник
3
Интересно, что аргумент в пользу этого countзаключается в том, что он изначально был сделан для массивов ... но объекты могут быть реализованы Countable, и вы можете передавать скалярные значения count()и получать действительный результат.
1
кол - () может возвращать 0 для переменной , которая не установлена, но она может также ... . Официальная документация с использованием модальных глаголов для выражения своей неопределенности: p
nawfal
Просто комментарий по существу isset(). Если вас беспокоят уведомления в PHP, вы должны уже объявить свой массив. Если вы позволите PHP динамически объявлять ваш массив, вы также получите уведомление в этот момент. Я думаю, что настоящий смысл предупреждения на php.net заключается в том, что вы не должны использовать его countдля определения, был ли массив объявлен или нет, поскольку он дает тот же результат, что и пустой массив.
Ной Дункан
12

Есть ли причина, по которой следует использовать счетчик вместо пустого при определении, пуст массив или нет?

Есть случаи, когда вам нужно что-то сделать с непустым массивом, зная его размер:

if( 0 < ( $cnt = count($array) ) )
{
 echo "Your array size is: $cnt";
}
else
 echo "Too bad, your array is empty :(";

Но я бы не рекомендовал использовать count, если вы не уверены на 100%, что вы считаете массив. В последнее время я занимался отладкой кода, в котором функция ошибки возвращалась FALSEвместо пустого массива, и я обнаружил следующее:

var_dump(count(FALSE));

вывод:

int 1

Итак, с тех пор я использую emptyили, if(array() === $array)чтобы быть уверенным, что у меня есть пустой массив .

dev-null-dweller
источник
6

count()похоже, лучше работает с интерфейсами, подобными массивам, которые реализуют ArrayAccess/Countable. empty()возвращает true для таких объектов, даже если у них нет элементов. Обычно эти классы реализуют Countableинтерфейс, поэтому если возникает вопрос «Содержит ли эта коллекция элементы?» не делая предположений о реализации, тогда count()это лучший вариант.

Райан
источник
Вы имеете в виду « emptyвозвращает false для таких объектов, даже если у них нет элементов»?
Alexw
Да. Не существует интерфейса, позволяющего классу определять, является он «пустым» или нет. И было бы бессмысленно там быть.
Райан
+1 Использование countбыло бы более гибким и расширяемым решением, если когда-либо для вашего кода будет иметь смысл принимать коллекцию, реализованную "обычным" способом ... ИМО, это может быть единственным подходящим критерием для определения того, используете ли вы countили другие способы ...
ClemC
Огромным недостатком версии count()7.2 является то, что она больше не может принимать пустые переменные.
Райан
5

В качестве альтернативы вы можете преобразовать переменную как логическое значение (неявно или явно):

if( $value )
{
  // array is not empty
}

if( (bool) $value )
{
  // array is still not empty
}

Этот метод генерирует, E_NOTICEесли переменная не определена, аналогично count().

Для получения дополнительной информации см. Страницу руководства PHP по сравнению типов .


источник
1
Это лучший способ проверить, используйте только в том empty()случае, если вы явно пытаетесь избежать запуска E_NOTICE (что, как правило, плохая идея, IMO). Явное использование пустого значения приведет к ошибкам в коде.
Cobby
3

Лично я предпочитаю элегантность кодирования (по отношению к моему конкретному варианту использования). Я согласен с Дэном МакГи, поскольку count () не отвечает с правильным типом данных (в данном случае логическим) для рассматриваемого теста, вынуждая разработчика написать больше кода для заполнения оператора if.

Оказывает ли это какое-либо существенное влияние на производительность, спорный вопрос только для очень больших массивов (для которых вам, вероятно, в любом случае не хватит распределения памяти в большинстве настроек).

В частности, когда дело доходит до массива PHP $ _POST, на мой взгляд, гораздо более «логично» написать / увидеть:

if ( !empty ( $_POST ) ) {
    // deal with postdata
}
Simonhamp
источник
3

Надеюсь, это может помочь кому-то, хотя на него уже был дан ответ (и что-то обсуждали). В моем собственном сценарии я знаю, что все мои массивы состоят из 7 элементов (проверки были выполнены ранее в моем коде), и я выполняю операцию, array_diffкоторая, конечно, возвращает нулевой массив при равенстве.

У меня было 34 секунды для countи 17 секунд для empty. Оба дают мне одинаковые вычисления, поэтому мой код все еще в порядке.

Однако вы также можете попробовать ==или ===как в PHP - проверьте, равны ли два массива . Лучшее, что я бы сказал, - это попробовать countvs emptyvs == empty array, а затем посмотреть, какой из них дает ваши собственные лучшие характеристики. В моем случае countбыл самым медленным, поэтому я использую emptyсейчас ... буду проверять serializeдальше

xchiltonx
источник
2

Нет веских причин отдавать предпочтение count($myArray) == 0большему empty($myArray). У них одинаковая семантика. Некоторые могут найти один более читабельным, чем другой. Один может работать немного лучше, чем другой, но вряд ли это будет существенным фактором для подавляющего большинства приложений php. Для всех практических целей выбор - дело вкуса.

Асаф
источник
1
А что насчет "производительности"? Использование объяснения «практических целей» приводит к вредным привычкам. Используйте, countкогда вам нужно подсчитать, используйте, emptyкогда вам нужно проверить, пуста ли коллекция. Конечно, есть крайние случаи, такие как строки или нули, но программист должен подумать о своем коде. Вы можете не соглашаться, вам разрешено.
Namek 09
иногда с count ($ myArray), если $ myArray является логическим, как значение FALSE, счетчик не работает (проверено на php5.3).
Mimouni
1

Иногда использование пустого является обязательным. Например этот код:

$myarray = array();

echo "myarray:"; var_dump($myarray); echo "<br>";
echo "case1 count: ".count($myarray)."<br>";
echo "case1 empty: ".empty($myarray)."<br>";

$glob = glob('sdfsdfdsf.txt');

echo "glob:"; var_dump($glob); echo "<br>";
echo "case2 count: ".count($glob)."<br>";
echo "case2 empty: ".empty($glob);

Если вы запустите этот код следующим образом: http://phpfiddle.org/main/code/g9x-uwi

Вы получите такой результат:

myarray:array(0) { } 
case1 count: 0
case1 empty: 1

glob:bool(false) 
case2 count: 1
case2 empty: 1

Поэтому, если вы countвыводите пустой глобус, вы получите неправильный результат. Вы должны проверить на пустоту.

Из документации glob :

Возвращает массив, содержащий совпадающие файлы / каталоги, пустой массив, если файл не найден, или FALSE в случае ошибки.
Примечание. В некоторых системах невозможно отличить пустое совпадение от ошибки.

Также проверьте этот вопрос: Почему count (false) возвращает 1?

транте
источник
1

Поскольку переменная, проанализированная как отрицательная, вернется int(1)сcount()

Я предпочитаю ($array === [] || !$array)проверять пустой массив.

Да, нам следует ожидать пустой массив, но не следует ожидать хорошей реализации функций без принудительных возвращаемых типов.

Примеры с count()

var_dump(count(0));
> int(1)
var_dump(count(false));
> int(1)
Sdlion
источник
0

Переделал, ребята, спасибо.

Хорошо, нет никакой разницы между использованием emptyи count. Технически его countследует использовать для массивов, а emptyтакже для массивов, а также для строк. Таким образом, в большинстве случаев они взаимозаменяемы, и если вы увидите документацию php, вы увидите список предложений, countесли вы находитесь в, emptyи наоборот.

Сарфраз
источник