Comprobación de matrices vacías: recuento vs vacío

98

Esta pregunta sobre ' Cómo saber si una matriz PHP está vacía ' me hizo pensar en esta pregunta

¿Hay alguna razón que countdeba usarse en lugar de emptycuando se determina si una matriz está vacía o no?

Mi pensamiento personal sería si los 2 son equivalentes para el caso de matrices vacías que debería usar emptyporque da una respuesta booleana a una pregunta booleana. De la pregunta vinculada anteriormente, parece que count($var) == 0es el método popular. Para mí, aunque técnicamente es correcto, no tiene sentido. Por ejemplo, Q: $ var, ¿estás vacío? A: 7 . Mmmm ...

¿Hay alguna razón por la que deba usar count == 0en su lugar o simplemente una cuestión de gusto personal?

Como lo señalaron otros en los comentarios para una respuesta ahora eliminada, counttendrá un impacto en el rendimiento para matrices grandes porque tendrá que contar todos los elementos, mientras que emptypuede detenerse tan pronto como sepa que no está vacío. Entonces, si dan los mismos resultados en este caso, pero countson potencialmente ineficientes, ¿por qué los usaríamos count($var) == 0?

Dan McGrath
fuente
Supongo que su intención es limitar la conversación exclusivamente a matrices, pero vale la pena señalar que el juego cambia por completo si está trabajando con objetos (por ejemplo, que implementan Countable, Iterator, etc.).
8
Una matriz vacía es igual a falseen PHP, sin necesidad de empty()o count().
Cobby
@Cobby Code por favor.
TheRealChx101
@ TheRealChx101 Como en, solo hazlo: if (!$myArray) { echo "array is empty"; } sandbox.onlinephpfunctions.com/code/…
Cobby
Hoy en día, la opción popular en la pregunta vinculada es usar empty().
PhoneixS

Respuestas:

97

Yo generalmente uso empty. No estoy seguro de por qué la gente usaría realmente el recuento: si la matriz es grande, el recuento lleva más tiempo / tiene más gastos generales. Si simplemente necesita saber si la matriz está vacía o no, utilice vacía.

prodigitalson
fuente
4
De hecho, estas funciones difieren cuando la matriz no está vacía.
Jacco
2
@Jacco: No estoy discutiendo eso. Pero si está probando que está vacío, no veo qué relevancia tiene; es una pregunta con un resultado booleano, que es lo que devolverá la función. En lo que respecta a lo que se considera vacío en, no vea cómo esos criterios producirían la respuesta incorrecta a menos que la var su prueba no sea una matriz, en cuyo caso ese es un problema completamente diferente.
prodigitalson
23
@prodigitalson Yo diría que la cuenta es O(1), ya que PHP almacena la cantidad de elementos internamente. Mira esta respuesta stackoverflow.com/a/5835419/592454
elitalon
4
@eliton: pero aún así, incluso si hay poca o ninguna diferencia en el rendimiento, ¿por qué usar el recuento si no necesita el recuento?
prodigitalson
4
empty () es demasiado indulgente con los errores. Acabo de pasar 2 horas depurando una subclase que probó empty () en una variable miembro privada de su superclase (el alcance de la variable miembro de la superclase DEBERÍA haber sido protegido, pero empty () no arrojó errores; el resultado fue simplemente algo que debería sucedió, no sucedió: la no existencia de la variable miembro en la subclase se trató exactamente de la misma manera como si esta variable miembro, una matriz, estuviera vacía, es decir, como si no tuviera elementos). Esto es problemático y es otro ejemplo de PHP demasiado indulgente.
Matthew Slyman
46

Tenía curiosidad por ver cuál era en realidad más rápido, así que hice un script simple para comparar esas funciones.

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

Como lo estaba haciendo, también intenté verificar el rendimiento al realizar operaciones que normalmente estarían asociadas con count () / empty ()

Usando 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

Uso de 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

Conclusiones si está usando PHP:

  1. empty () es mucho más rápido que count () en ambos escenarios, con una matriz vacía y poblada

  2. count () realiza lo mismo con una matriz llena o vacía.

  3. Hacer un IF simple o simplemente una operación booleana es lo mismo.

  4. IF / ELSE es ligeramente más eficiente que (?:). A menos que esté haciendo miles de millones de iteraciones con expresiones en el medio, es completamente insignificante.

Conclusiones si está usando HHVM:

  1. empty () es un poquito más rápido que count () pero insignificantemente.

    [El resto es igual que en PHP]

En conclusión, si solo necesita saber si la matriz está vacía, utilice siempre empty ();

Esta fue solo una prueba curiosa simplemente hecha sin tener en cuenta muchas cosas. Es solo una prueba de concepto y podría no reflejar las operaciones en producción.

Satake
fuente
Gracias por el código de prueba de muestra ... Lo acabo de usar y descubrí que if($x){es más rápido que if(empty($x)){(solo funciona si sabes que $xse ha declarado).
Redzarf
Tu código de prueba es realmente malo. Agregas muchas cosas adicionales, como una llamada de función anónima. Si elimino y ejecuto el código básico (para ciclos uno tras otro), obtengo una gran diferencia. Y me refiero a que, en ese caso, más rápido si no hay county emptyllamadas en la declaración if. Luego viene el emptyy dura el count. Pero comparado con el tuyo en su caso, el vacío es diez veces más rápido Prueba de matriz simple: 0.104662, vacío: 0.177659, recuento: 1.175125 en PHP 5.6, de lo contrario, su código da el mismo resultado en esta versión también como lo mencionó. Solo son resultados falsos.
golddragon007
16

Creo que es solo una preferencia personal. Algunas personas podrían decir que emptyes más rápido (por ejemplo, http://jamessocol.com/projects/count_vs_empty.php ) mientras que otras podrían decir que countes mejor, ya que originalmente se hizo para matrices.emptyes más general y se puede aplicar a otros tipos.

php.net da la siguiente advertencia count:

count () puede devolver 0 para una variable que no está establecida, pero también puede devolver 0 para una variable que se ha inicializado con una matriz vacía. Utilice isset () para probar si se establece una variable.

En otras palabras, si la variable no está configurada, recibirá un aviso de PHP diciendo que no está definida. Por tanto, antes de usar count, sería preferible comprobar la variable con isset. Esto no es necesario con empty.

Laurent le Beau-Martin
fuente
3
Es interesante que un argumento a favor countsea ​​que se hizo originalmente para matrices ... sin embargo, los objetos se pueden implementar Countabley puedes pasar valores escalares count()y obtener un resultado válido.
1
count () puede devolver 0 para una variable que no está definida, pero puede también ... . Documentación oficial que usa verbos modales para expresar su incertidumbre: p
nawfal
Solo un comentario sobre el isset()punto. Si le preocupan los avisos en PHP, ya debería haber declarado su matriz. Si deja que PHP declare dinámicamente su matriz, también recibirá un aviso en ese punto. Creo que el verdadero punto de la advertencia en php.net es que no debe usar countpara determinar si una matriz ha sido declarada o no, ya que produce el mismo resultado que una matriz vacía.
Noah Duncan
12

¿Hay alguna razón por la que se deba usar el recuento en lugar de vacío al determinar si una matriz está vacía o no?

Hay, cuando necesita hacer algo en una matriz no vacía sabiendo su tamaño:

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

Pero no recomendaría usar count, a menos que esté 100% seguro de que lo que está contando es una matriz. Últimamente he estado depurando código, donde la función de error regresaba en FALSElugar de una matriz vacía, y lo que descubrí fue:

var_dump(count(FALSE));

salida:

int 1

Entonces, desde entonces, estoy usando emptyo if(array() === $array)para estar seguro de que tengo una matriz vacía.

dev-null-dweller
fuente
6

count()parece funcionar mejor con interfaces tipo matriz que implementan ArrayAccess/Countable. empty()devuelve verdadero para este tipo de objetos incluso si no tienen elementos. Normalmente, estas clases implementarán la Countableinterfaz, por lo que si la pregunta es "¿Esta colección contiene elementos?" sin hacer una suposición sobre la implementación, entonces count()es una mejor opción.

Ryan
fuente
¿Quiere decir " emptydevuelve falso para este tipo de objetos incluso si no tienen elementos"?
alexw
Si. No existe una interfaz que permita a una clase definir si está "vacía" o no. Y realmente no tendría sentido que hubiera uno.
Ryan
+1 Usar countsería una solución más flexible y extensible si alguna vez tiene sentido que su código acepte una colección implementada de una manera "común" ... OMI, ese podría ser el único criterio pertinente para definir si usa countu otras formas ...
ClemC
La gran desventaja de la versión count()7.2 es que ya no puede tomar variables vacías.
Ryan
5

Alternativamente, puede convertir la variable como un booleano (implícita o explícitamente):

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

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

Este método genera un E_NOTICEsi la variable no está definida, de manera similar acount() .

Para obtener más información, consulte la página del Manual de PHP sobre comparaciones de tipos .


fuente
1
Esta es la mejor manera de verificar, solo úsela empty()si está tratando explícitamente de evitar activar un E_NOTICE (que generalmente es una mala idea, en mi opinión). El uso descarado de empty conducirá a un código defectuoso.
Cobby
3

Mi preferencia personal es más por la elegancia de la codificación (en relación con mi caso de uso específico). Estoy de acuerdo con Dan McG en la medida en que count () no responde con el tipo de datos correcto (en este caso booleano) para la prueba en cuestión, lo que obliga al desarrollador a escribir más código para completar una declaración 'if'.

Si esto tiene un impacto significativo en el rendimiento solo es discutible para arreglos extremadamente grandes (para los cuales probablemente no tendrá suficiente asignación de memoria en la mayoría de las configuraciones).

Particularmente cuando se trata de la matriz $ _POST de PHP, parece mucho más "lógico" en mi opinión escribir / ver:

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

Espero que esto pueda ayudar a alguien a pesar de que ya ha sido respondido (y debatido algo sobre qué). En mi propio escenario, sé que todas mis matrices tienen 7 elementos (las verificaciones se realizaron anteriormente en mi código) y estoy realizando unaarray_diff que, por supuesto, devuelve una matriz de cero cuando es igual.

Tuve 34 segundos para county 17 segundos para empty. Ambos me dan los mismos cálculos, por lo que mi código sigue estando bien.

Sin embargo, también puede probar ==o ===como en PHP: compruebe si dos matrices son iguales . Lo mejor que diría es probar countvs emptyvs == empty array, luego ver cuál da sus mejores resultados. En mi caso countfue el más lento, así que lo estoy usando emptyahora ... lo veré a serializecontinuación

xchiltonx
fuente
2

No hay una fuerte razón para preferir count($myArray) == 0más empty($myArray). Tienen una semántica idéntica. Algunos pueden encontrar uno más legible que el otro. Uno puede funcionar ligeramente mejor que el otro, pero no es probable que sea un factor significativo en la gran mayoría de las aplicaciones php. A todos los efectos prácticos, la elección es cuestión de gustos.

Asaf
fuente
1
¿Qué pasa con la "actuación"? Usar la explicación de "propósitos prácticos" conduce a malos hábitos. Úselo countcuando necesite contar, utilícelo emptycuando necesite verificar si la colección está vacía. Por supuesto, hay casos extremos como cadenas o nulos, pero el programador debe pensar en su código. Puede no estar de acuerdo, está permitido.
Namek
algunas veces, con count ($ myArray) si $ myArray es un booleen como un valor FALSE, el recuento no funciona (probado en php5.3).
Mimouni
1

A veces, usar vacío es imprescindible. Por ejemplo este código:

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

Si ejecuta este código así: http://phpfiddle.org/main/code/g9x-uwi

Obtienes esta salida:

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

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

Así que si usted count obtiene la salida glob vacía, obtendrá una salida incorrecta. Debes comprobar si hay vacío.

De la documentación glob :

Devuelve una matriz que contiene los archivos / directorios coincidentes, una matriz vacía si ningún archivo coincide o FALSE en caso de error.
Nota: en algunos sistemas es imposible distinguir entre una coincidencia vacía y un error.

También verifique esta pregunta: ¿Por qué contar (falso) devolver 1?

trante
fuente
1

Dado que una variable analizada como negativa volvería int(1)concount()

Prefiero ($array === [] || !$array)probar una matriz vacía.

Sí, deberíamos esperar una matriz vacía, pero no deberíamos esperar una buena implementación en funciones sin tipos de retorno forzados.

Ejemplos con count()

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

Rehice mi mente chicos, gracias.

Ok, no hay diferencia entre el uso de emptyy count. Técnicamente, countdebería usarse para matrices y emptypodría usarse tanto para matrices como para cadenas. Entonces, en la mayoría de los casos, son intercambiables y si ve los documentos php, verá la lista de sugerencias de countsi está en emptyy viceversa.

Sarfraz
fuente