Проверка наличия пустых массивов: считать против пустых

73

Этот вопрос в вопросе 'Как узнать, пуст ли PHP пуст." Я думал об этом вопросе

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

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

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

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

  • 0
    Я предполагаю, что вы намерены ограничить разговор исключительно массивами, но, возможно, стоит отметить, что игра полностью меняется, если вы работаете с объектами (например, реализующими Countable, Iterator и т. Д.).
  • 7
    Пустой массив равен false в PHP - нет необходимости в empty() или count() .
Показать ещё 3 комментария
Теги:
arrays
performance
semantics
standards

12 ответов

78
Лучший ответ

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

  • 4
    Эти функции действительно отличаются, когда массив не пустой.
  • 1
    @Jacco: Я не оспариваю это. Но если вы тестируете его пустым, я не вижу, какое это имеет отношение - это вопрос с логическим результатом, который возвращает функция. Что касается того, что считается пустым, то не видите, как эти критерии будут давать неправильный ответ, если только тестирование не является массивом, в этом случае это совершенно другая проблема.
Показать ещё 11 комментариев
28

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

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

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

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

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

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

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

  • empty() является младшим битем быстрее, чем count(), но незначительно.

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

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

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

  • 0
    Спасибо за пример кода тестирования .... Я просто использовал его и обнаружил, что if($x){ быстрее, чем if(empty($x)){ (работает, только если вы знаете, что $x был объявлен).
15

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

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

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

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

  • 3
    Интересно, что аргумент в пользу count заключается в том, что он изначально был создан для массивов ... однако объекты могут реализовывать Countable , и вы можете передавать скалярные значения в count() и получать действительный результат.
  • 1
    count () может вернуть 0 для переменной, которая не установлена, но может также .... Официальная документация с использованием модальных глаголов для выражения своей неопределенности: p
Показать ещё 1 комментарий
9

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

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

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), чтобы убедиться, что у меня есть массив, который пуст.

5

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

  • 0
    Вы имеете в виду « empty возвращает ложь для таких объектов, даже если у них нет элементов»?
  • 0
    Да. Нет интерфейса, позволяющего классу определять, является ли он «пустым» или нет. И не было бы никакого смысла в том, чтобы быть таким.
Показать ещё 2 комментария
4

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

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

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

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

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

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

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

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

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

3

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

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

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

if ( !empty ( $_POST ) ) {
    // deal with postdata
}
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 вы получаете неправильный вывод. Вы должны проверить пустоту.

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

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

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

1

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

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

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

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

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

Примеры с count()

var_dump(count(0));
> int(1)
var_dump(count(false));
> int(1)
0

Я переделаю своих ребята, спасибо.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню