Перевірка порожніх масивів: рахувати проти порожніх


98

Це питання на тему " Як дізнатися, чи масив PHP порожній ", змусив мене задуматися над цим питанням

Чи є причина, яку countслід використовувати замість того, emptyщоб визначати, чи масив порожній чи ні?

Моя особиста думка була б, якщо два еквівалента для випадків порожніх масивів, які ви повинні використовувати, emptyоскільки це дає бульну відповідь на булеве питання. З вищезазначеного питання, мабуть, count($var) == 0це популярний метод. Мені, хоча технічно правильно, немає сенсу. Наприклад Q: $ var, ти порожній? A: 7 . Гммм ...

Чи є причина, яку я повинен використовувати count == 0замість цього, або лише питання особистого смаку?

Як вказували інші у коментарях до тепер видаленої відповіді, countце матиме ефективність для великих масивів, оскільки вона повинна буде рахувати всі елементи, тоді як emptyможе зупинятися, як тільки знає, що вона не порожня. Отже, якщо вони дають однакові результати в цьому випадку, але countпотенційно неефективні, то чому б ми коли-небудь використовували count($var) == 0?


Я припускаю, що ваш намір полягає в обмеженні розмови виключно масивами, але, можливо, варто зазначити, що гра повністю змінюється, якщо ви працюєте з об'єктами (наприклад, що реалізують Countable, Iterator тощо).

8
Порожній масив дорівнює falsePHP - не потрібно empty()або count().
Коббі

@Cobby Code будь ласка.
TheRealChx101

@ TheRealChx101 Як і раніше, просто робіть: if (!$myArray) { echo "array is empty"; } sandbox.onlinephpfunctions.com/code/…
Коббі

В даний час використовується популярний варіант у пов'язаному питанні empty().
PhoneixS

Відповіді:


97

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


4
Ці функції дійсно відрізняються, коли масив не порожній.
Жако

2
@Jacco: Я не заперечую це. Але якщо ви випробовуєте його порожнім, я не бачу, яка актуальність - це питання з булевим результатом, який функція поверне. Що стосується того, що вважається порожнім, не дивіться, як ці критерії дають неправильну відповідь, якщо тільки вар тестування не буде масивом, у випадку якого зовсім інша проблема.
блудники

23
@prodigitalson Я б сказав, що підрахунок є O(1), оскільки PHP зберігає кількість елементів всередині. Перевірте цей відповідь stackoverflow.com/a/5835419/592454
elitalon

4
@eliton: але все ж - навіть у тому випадку, якщо різниця у продуктивності є малою або незначною, навіщо використовувати підрахунок, якщо ти не потрібен?
блудники

4
empty () занадто прощає помилок. Я щойно провів 2 години налагодження підкласу, який тестував порожній () на змінній приватному члені свого суперкласу (область змінної члена суперкласу ОБОВ'ЯЗАНА була захищена, але порожня () не повертала жодних помилок - у результаті було просто щось, що повинно сталося, не сталося: неіснуюча змінна-член у підкласі трактувалася точно так само, як якщо б ця змінна-член, масив, була порожньою - тобто, як би не мала елементів). Це проблематично, і ще один приклад PHP занадто прощає.
Меттью Сліман

46

Мені було цікаво побачити, який з них насправді швидший, тому я створив простий сценарій для порівняння цих функцій.

<?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 () - підлітковий-weeny трохи швидше, ніж count (), але незначно.

    [Решта така ж, як у PHP]

На закінчення висновку, якщо вам просто потрібно знати, чи масив порожній, завжди використовуйте порожній ();

Це було просто цікаве випробування, просто зроблене без урахування багатьох речей. Це лише доказ концепції та може не відображати операцій у виробництві.


Дякую за зразок тестового коду .... Я тільки що скористався ним і виявив, що if($x){це швидше, ніж if(empty($x)){(працює лише, якщо ви знаєте, що $xбуло оголошено).
Редзарф

Ваш тестовий код дуже поганий. Ви додаєте багато додаткових матеріалів, як-от виклик функції аноніму. Якщо я видаляю і просто запускаю голий код (для циклу один за одним), то я отримую величезну різницю. І я маю на увазі в такому випадку швидше, якщо в операторі if немає countі emptyдзвінків. Потім він приходить emptyі триває count. Але в порівнянні з вашим в голому випадку, порожнє - в десять разів швидше! Простий тест масиву: 0.104662, порожній: 0.177659, кількість: 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 :(";

Але я б не рекомендував використовувати підрахунок, якщо ви не впевнені на 100%, що те, що ви рахуєте, це масив. Останнім часом я налагоджував код, де функція помилки поверталася FALSEзамість порожнього масиву, і що я виявив:

var_dump(count(FALSE));

вихід:

int 1

Тож я відтоді використовую emptyчи if(array() === $array)впевнений, що у мене масив порожній.


6

count()Здається, краще працює з інтерфейсними інтерфейсами, які реалізуються ArrayAccess/Countable. empty()повертає істину для таких видів об'єктів, навіть якщо вони не мають елементів. Зазвичай ці класи будуть реалізовувати Countableінтерфейс, тому якщо питання "Чи містить ця колекція елементи?" не роблячи припущення щодо реалізації, тоді count()є кращим варіантом.


Ви маєте на увазі " emptyповертає помилки для таких видів об'єктів, навіть якщо вони не мають елементів"?
alexw

Так. Немає інтерфейсу, який би дозволяв класу визначати, чи він "порожній" чи ні. І насправді не було б сенсу існувати.
Райан

+1 Використання countбуло б більш гнучким і розширюваним рішенням, якщо коли-небудь має сенс ваш код приймати колекцію, реалізовану "загальним" способом ... IMO, який може бути єдиним відповідним критерієм визначення, якщо ви використовуєте countчи іншими способами ...
ClemC

Величезний мінус count()7,2 - це те, що він більше не може приймати порожні змінні.
Райан

5

Крім того, ви можете вказати змінну як булева (неявно або явно):

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

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

Цей метод генерує a, E_NOTICEякщо змінна не визначена, аналогічно до count().

Для отримання додаткової інформації див порівняння типів посібника PHP .


1
Це найкращий спосіб перевірити, використовуйте його лише empty()тоді, коли ви явно намагаєтесь уникнути запуску E_NOTICE (що, як правило, погана ідея, IMO). Нахабне використання порожнього призведе до помилок коду.
Коббі

3

Мої особисті переваги більше стосуються елегантності кодування (стосовно мого конкретного випадку використання). Я погоджуюся з Деном Макгом, оскільки count () не відповідає правильному типу даних (в даному випадку булевим) для відповідного тесту змушує розробника написати більше коду для заповнення заяви "if".

Чи має це якийсь істотний вплив на продуктивність, спірним є лише надзвичайно великий масив (якому, мабуть, у більшості налаштувань все одно не вистачить пам'яті).

Особливо, коли мова йде про масив $ _POST PHP, на мою думку, здається набагато "логічнішим" написати / побачити:

if ( !empty ( $_POST ) ) {
    // deal with postdata
}

3

Сподіваюсь, це може комусь допомогти, хоча на нього вже відповіли (і дебютували дещо). У моєму власному сценарії я знаю, що всі мої масиви мають 7 елементів (перевірки були зроблені раніше в моєму коді), і я виконую такий, array_diffякий, звичайно, повертає масив нуля при рівності.

У мене було 34 сек countі 17 сек empty. Обидва дають мені однакові розрахунки, тому мій код все ще чудово.

Однак ви також можете спробувати ==або ===як у PHP - Перевірте, чи два масиви рівні . Найкраще, як я б сказав, спробуйте countпроти emptyvs == empty array, а потім подивіться, що дає найкращі результати. У моєму випадку countбув найповільнішим , так я використовую в emptyданий час ... перевірятимуть serializeнаступний


2

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


1
А що з "виставою"? Використання пояснення "практичних цілей" призводить до шкідливих звичок. Використовуйте, countколи вам потрібно рахувати, використовувати, emptyколи вам потрібно перевірити, чи колекція порожня. Звичайно, бувають крайні випадки, такі як рядки або нулі, але програмісту потрібно подумати над своїм кодом. Ви можете погодитися, вам це дозволено.
Імек

інколи, з count ($ myArray), якщо $ myArray булева, як значення FALSE, кількість не працює (перевірено на php5.3).
Мімуні

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порожній глобальний вихід, ви отримаєте неправильний вихід. Слід перевірити наявність порожнечі.

З глобальної документації:

Повертає масив, що містить відповідні файли / каталоги, порожній масив, якщо жоден файл не відповідає або FALSE за помилкою.
Примітка. У деяких системах неможливо відрізнити порожній збіг від помилки.

Також перевірте це питання: Чому підраховують (помилкове) повернення 1?


1

Оскільки змінна, проаналізована як негативна, повернеться 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і навпаки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.