Sprawdzanie pustych tablic: count vs empty


98

Pytanie „ Jak sprawdzić, czy tablica PHP jest pusta ” sprawiło, że pomyślałem o tym pytaniu

Czy istnieje powód, którego countnależy używać zamiast emptyprzy określaniu, czy tablica jest pusta, czy nie?

Moim osobistym pomysłem byłoby, gdyby 2 były równoważne w przypadku pustych tablic, których powinieneś użyć, emptyponieważ daje logiczną odpowiedź na pytanie boolowskie. Z powyższego pytania wynika, że count($var) == 0jest to popularna metoda. Dla mnie, chociaż technicznie poprawne, nie ma sensu. Np. P: $ var, czy jesteś pusty? Odp .: 7 . Hmmm...

Czy jest jakiś powód, dla którego powinienem użyć count == 0zamiast tego, czy tylko kwestia osobistego gustu?

Jak zauważyli inni w komentarzach do teraz usuniętej odpowiedzi, countbędzie miał wpływ na wydajność w przypadku dużych tablic, ponieważ będzie musiał liczyć wszystkie elementy, podczas gdy emptymoże zatrzymać się, gdy tylko dowie się, że nie jest pusty. Jeśli więc dają takie same wyniki w tym przypadku, ale countsą potencjalnie nieefektywne, dlaczego mielibyśmy kiedykolwiek używać count($var) == 0?


Zakładam, że twoim zamiarem jest ograniczenie konwersacji wyłącznie do tablic, ale warto zauważyć, że gra zmienia się całkowicie, jeśli pracujesz z obiektami (np. Implementującymi Countable, Iterator itp.).

8
Pusta tablica jest równa falsew PHP - nie ma potrzeby używania empty()lub count().
Cobby,

@Cobby Code, proszę.
TheRealChx101

@ TheRealChx101 Jak w, po prostu zrób: if (!$myArray) { echo "array is empty"; } sandbox.onlinephpfunctions.com/code/…
Cobby

Obecnie popularną opcją w powiązanym pytaniu jest użycie empty().
PhoneixS

Odpowiedzi:


97

Generalnie używam empty. Nie jestem pewien, dlaczego ludzie naprawdę używaliby count - jeśli tablica jest duża, count trwa dłużej / ma więcej narzutów. Jeśli po prostu chcesz wiedzieć, czy tablica jest pusta, użyj pustego.


4
Te funkcje rzeczywiście różnią się, gdy tablica nie jest pusta.
Jacco,

2
@Jacco: Nie kwestionuję tego. Ale jeśli testujesz go, jest pusty, nie widzę, jakie ma to znaczenie - jest to pytanie z wynikiem boolowskim, które funkcja zwróci. Jeśli chodzi o to, co jest uważane za puste, nie patrz, w jaki sposób te kryteria dałyby złą odpowiedź, chyba że zmienna, którą testujesz, nie jest tablicą, w którym to przypadku jest to zupełnie inny problem.
prodigitalson

23
@prodigitalson Powiedziałbym, że count to O(1), ponieważ PHP przechowuje wewnętrznie liczbę elementów. Zapoznaj się z tą odpowiedzią stackoverflow.com/a/5835419/592454
elitalon

4
@eliton: ale nadal - nawet jeśli nie ma różnicy w wydajności lub jest niewielka, po co używać count, jeśli nie potrzebujesz count?
prodigitalson

4
Empty () zbyt wybacza błędy. Właśnie spędziłem 2 godziny na debugowaniu podklasy, która przetestowała pustą () na prywatnej zmiennej składowej jej nadklasy (zakres zmiennej składowej nadklasy POWINIEN być chroniony, ale empty () nie zwróciło żadnych błędów - wynik był taki, że coś powinno zdarzyło się, nie wydarzyło się: nieistnienie zmiennej składowej w podklasie było traktowane dokładnie tak samo, jak gdyby ta zmienna składowa, tablica, była pusta - tj. jakby nie miała elementów). Jest to problematyczne i kolejny przykład na to, że PHP jest zbyt wyrozumiałe.
Matthew Slyman,

46

Byłem ciekawy, który z nich jest tak naprawdę szybszy, więc stworzyłem prosty skrypt do testowania tych funkcji.

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

Ponieważ to robiłem, próbowałem również sprawdzić wydajność wykonując operacje, które normalnie byłyby powiązane z count () / empty ()

Używając 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

Korzystanie z 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

Wnioski, jeśli używasz PHP:

  1. Empty () jest znacznie szybsza niż count () w obu scenariuszach, z pustą i wypełnioną tablicą

  2. count () wykonuje to samo z pełną lub pustą tablicą.

  3. Wykonywanie prostego JEŻELI lub tylko operacji logicznej jest takie samo.

  4. IF / ELSE jest nieco bardziej wydajne niż (?:). O ile nie wykonujesz miliardów iteracji z wyrażeniami pośrodku, jest to całkowicie nieistotne.

Wnioski, jeśli używasz HHVM:

  1. empty () jest trochę szybsze niż count (), ale nieznacznie.

    [Reszta jest taka sama jak w PHP]

Podsumowując wniosek, jeśli chcesz tylko wiedzieć, czy tablica jest pusta, zawsze użyj pustego ();

To był po prostu ciekawy test, po prostu wykonany bez uwzględnienia wielu rzeczy. To tylko dowód koncepcji i może nie odzwierciedlać operacji w produkcji.


Dzięki za przykładowy kod testowy ... Właśnie go użyłem i stwierdziłem, że if($x){jest szybszy niż if(empty($x)){(działa tylko wtedy, gdy wiesz, że $xzostał zadeklarowany).
Redzarf

Twój kod testowy jest naprawdę zły. Dodajesz wiele dodatkowych rzeczy, takich jak wywołanie funkcji anonimowej. Jeśli usunę i po prostu uruchomię goły kod (cykl po sobie), dostaję ogromną różnicę. I mam na myśli w tym przypadku szybciej, jeśli nie ma counti emptywywołuje w instrukcji if. Potem przychodzi emptyi trwa count. Ale w porównaniu do twojego w gołej obudowie, pusty jest dziesięć razy szybciej! Prosty test tablicowy: 0,104662, pusty: 0,177659, liczba: 1,175125 w PHP 5.6, w przeciwnym razie kod daje taki sam wynik w tej wersji, jak wspomniany. To tylko fałszywe wyniki.
golddragon007

16

Myślę, że to tylko osobiste preferencje. Niektórzy mogą powiedzieć, że emptyjest szybszy (np. Http://jamessocol.com/projects/count_vs_empty.php ), podczas gdy inni mogą powiedzieć, że countjest lepszy, ponieważ został pierwotnie stworzony dla tablic. emptyjest bardziej ogólny i można go zastosować do innych typów.

php.net daje jednak następujące ostrzeżenie count:

count () może zwrócić 0 dla zmiennej, która nie jest ustawiona, ale może również zwrócić 0 dla zmiennej, która została zainicjowana pustą tablicą. Użyj isset (), aby sprawdzić, czy zmienna jest ustawiona.

Innymi słowy, jeśli zmienna nie jest ustawiona, PHP dostanie powiadomienie, że jest niezdefiniowana. Dlatego przed użyciem countlepiej byłoby sprawdzić zmienną za pomocą isset. Nie jest to konieczne w przypadku empty.


3
Interesujące jest to, że argumentem przemawiającym za argumentem countjest to, że pierwotnie został on utworzony dla tablic ... ale obiekty mogą implementować Countable, a także można przekazywać wartości skalarne count()i uzyskiwać poprawny wynik.

1
count () może zwrócić 0 dla zmiennej, która nie jest ustawiony, ale może też ... . Oficjalna dokumentacja wykorzystująca czasowniki modalne do wyrażenia swojej niepewności: p
nawfal

Tylko komentarz do tego isset()punktu. Jeśli martwisz się powiadomieniami w PHP, powinieneś już zadeklarować swoją tablicę. Jeśli pozwolisz PHP dynamicznie zadeklarować twoją tablicę, otrzymasz powiadomienie w tym momencie. Myślę, że prawdziwym celem ostrzeżenia na php.net jest to, że nie powinieneś używać countdo określania, czy tablica została zadeklarowana, czy nie, ponieważ daje to ten sam wynik, co pusta tablica.
Noah Duncan

12

Czy istnieje powód, dla którego należy używać count zamiast pustego podczas określania, czy tablica jest pusta, czy nie?

Jest, gdy musisz coś zrobić na niepustej tablicy, znając jej rozmiar:

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

Ale nie polecałbym używania count, chyba że masz 100% pewności, że liczysz tablicę. Ostatnio debugowałem kod, w którym funkcja błędu zwracała FALSEzamiast pustej tablicy, a odkryłem:

var_dump(count(FALSE));

wynik:

int 1

Od tego czasu używam emptylub, if(array() === $array)aby mieć pewność, że mam tablicę, która jest pusta.


6

count()wydaje się działać lepiej z interfejsami podobnymi do tablic, które implementują ArrayAccess/Countable. empty()zwraca prawdę dla tego rodzaju obiektów, nawet jeśli nie mają one żadnych elementów. Zazwyczaj te klasy implementują Countableinterfejs, więc jeśli pytanie brzmi „Czy ta kolekcja zawiera elementy?” bez robienia założeń co do implementacji, count()jest to lepsza opcja.


Czy masz na myśli „ emptyzwraca fałsz dla tego rodzaju obiektów, nawet jeśli nie mają one elementów”?
alexw

Tak. Nie ma interfejsu, który pozwoliłby klasie określić, czy jest „pusta”, czy nie. I nie miałoby sensu, żeby taki był.
Ryan

+1 Używanie countbyłoby bardziej elastycznym i rozszerzalnym rozwiązaniem, gdyby kiedykolwiek miał sens, aby Twój kod akceptował kolekcję zaimplementowaną w „powszechny” sposób… IMO to może być jedyne stosowne kryterium do określenia, czy używasz countlub w inny sposób ...
ClemC

Ogromną wadą wersji count()7.2 jest to, że nie może już przyjmować pustych zmiennych.
Ryan

5

Alternatywnie możesz rzutować zmienną jako wartość logiczną (niejawnie lub jawnie):

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

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

Ta metoda generuje an, E_NOTICEjeśli zmienna nie jest zdefiniowana, podobnie jak count().

Aby uzyskać więcej informacji, zobacz stronę podręcznika PHP poświęconą porównaniom typów .


1
To najlepszy sposób sprawdzenia, używaj tylko empty()wtedy, gdy jawnie próbujesz uniknąć wyzwalania E_NOTICE (co jest ogólnie złym pomysłem, IMO). Rażąco użycie pustego spowoduje błędny kod.
Cobby,

3

Osobiście wolę bardziej elegancję kodowania (w odniesieniu do mojego konkretnego przypadku użycia). Zgadzam się z Danem McG, ponieważ count () nie odpowiada poprawnym typem danych (w tym przypadku logicznym) dla danego testu, zmuszając programistę do napisania większej ilości kodu w celu wypełnienia instrukcji „if”.

To, czy ma to jakikolwiek znaczący wpływ na wydajność, jest dyskusyjne tylko w przypadku bardzo dużych tablic (dla których i tak prawdopodobnie nie będziesz mieć wystarczającej ilości pamięci w większości konfiguracji).

Szczególnie jeśli chodzi o tablicę $ _POST PHP, moim zdaniem bardziej "logiczne" wydaje się pisanie / oglądanie:

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

3

Mam nadzieję, że może to komuś pomóc, nawet jeśli już udzielono odpowiedzi (i debatowaliśmy nad czym). W moim własnym scenariuszu wiem, że wszystkie moje tablice mają 7 elementów (kontrole zostały wykonane wcześniej w moim kodzie) i wykonuję operację, array_diffktóra oczywiście zwraca tablicę zerową, gdy jest równa.

Miałem 34 sekundy na counti 17 sekund na empty. Oba dają mi te same obliczenia, więc mój kod jest nadal w porządku.

Możesz jednak wypróbować ==lub ===jak w PHP - Sprawdź, czy dwie tablice są równe . Najlepsze, co powiedziałbym, to spróbuj countvs emptyvs == empty array, a potem zobacz, który daje najlepsze osiągi. W moim przypadku countbyło najwolniej więc używam emptyteraz ... będę sprawdzać serializedalej


2

Nie ma powodu, aby silna wolą count($myArray) == 0ponad empty($myArray). Mają identyczną semantykę. Niektórzy mogą uznać, że jeden jest bardziej czytelny niż drugi. Jedna może działać nieznacznie lepiej niż druga, ale prawdopodobnie nie będzie istotnym czynnikiem w większości aplikacji php. Ze wszystkich praktycznych powodów wybór jest kwestią gustu.


1
A co z „wydajnością”? Wyjaśnianie „celów praktycznych” prowadzi do złych nawyków. Użyj, countgdy potrzebujesz liczyć, użyj, emptygdy chcesz sprawdzić, czy kolekcja jest pusta. Oczywiście istnieją przypadki skrajne, takie jak łańcuchy lub wartości null, ale programista musi pomyśleć o swoim kodzie. Możesz się nie zgodzić, masz pozwolenie.
Namek

czasami, z count ($ myArray), jeśli $ myArray jest wartością logiczną, taką jak FALSE, licznik nie działa (testowane na php5.3).
Mimouni

1

Czasami użycie pustego jest koniecznością. Na przykład ten kod:

$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);

Jeśli uruchomisz ten kod w ten sposób: http://phpfiddle.org/main/code/g9x-uwi

Otrzymasz ten wynik:

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

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

Więc jeśli ty count puste wyjście glob, otrzymujesz zły wynik. Powinieneś sprawdzić pustkę.

Z dokumentacji glob :

Zwraca tablicę zawierającą dopasowane pliki / katalogi, pustą tablicę, jeśli żaden plik nie został dopasowany lub FALSE w przypadku błędu.
Uwaga: W niektórych systemach nie można odróżnić pustego dopasowania od błędu.

Sprawdź również to pytanie: Dlaczego count (false) return 1?


1

Ponieważ zmienna przeanalizowana jako ujemna zwróciłaby int(1)zcount()

wolę ($array === [] || !$array) testować pustą tablicę.

Tak, powinniśmy oczekiwać pustej tablicy, ale nie powinniśmy oczekiwać dobrej implementacji funkcji bez wymuszonych typów zwracanych.

Przykłady z count()

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

0

Przerobiłem swój umysł, dzięki.

Ok, nie ma różnicy między używaniem emptya count. Z technicznego punktu countwidzenia powinno być używane dla tablic i emptymoże być używane zarówno dla tablic, jak i ciągów. Więc w większości przypadków są one wymienne i jeśli zobaczysz dokumenty php, zobaczysz listę sugestii, countczy jesteś w tym miejscu emptyi odwrotnie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.