¿Por qué PHP trata "0" como FALSO en contextos booleanos?
12
"0", como una cadena que contiene un carácter, no es algo vacío intuitivamente. ¿Por qué PHP lo trata como FALSO cuando se convierte a un booleano, a diferencia de otros lenguajes de programación?
duplicado de: stackoverflow.com/questions/523643/… . Es lo mismo tanto en PHP como en JavaScript. Verifique la respuesta aceptada a continuación.
Walfrat
55
Se debe a que PHP hace todo lo posible para ser tan inconsistente, tanto con sí mismo como con cualquier otro lenguaje de programación, como sea posible.
David Arno
2
@DavidArno Por el contrario, está haciendo todo lo posible para ser coherente ; una vez que comience la transmisión automática de cadenas (muy útil en un idioma que a menudo toma vars de URL o cuerpos de solicitud), debe seguir esa lógica. Si '0'se trata como 0en $x + 1, ¿por qué no debería tratarse también como 0, y por lo tanto false, en if ( $x )?
IMSoP
1
@DavidArno exactamente;)
linuxunil
1
@DavidArno Una vez que comienzas a realizar lanzamientos con pérdida, creo que es inevitable alguna inconsistencia; la solución consistente implica rechazar algunos moldes y diseñar el resto con mucho cuidado. Sin embargo, muy pocos lenguajes populares están diseñados desde cero; La mayoría evoluciona a partir de experimentos accidentalmente populares o de idiomas más antiguos con diferentes objetivos y equipaje. Incluso C #, que tiene mucho diseño teórico sólido, tiene un legado de C, que nunca tuvo la intención de ser tan universal como se convirtió. Snark como "hacer todo lo posible para ser inconsistente" es como gritarle al árbitro en un partido deportivo.
IMSoP
Respuestas:
12
PHP fue diseñado (o, más bien, evolucionado) para su uso con solicitudes web, donde se trata con frecuencia de entrada de cadena (parámetros de URL o solicitudes POST de un formulario en un navegador). Como tal, automáticamente lanzará cadenas a otros tipos.
Un ejemplo simple de esto es que '1' + '2'da 3, no un error, o '12', o alguna otra interpretación. Por la misma lógica, la cadena '0'se puede usar como un número 0.
Mientras tanto, como muchos lenguajes, PHP trata ciertos valores como "falsos" cuando se convierten en booleanos, que son intuitivamente "vacíos", como usted dice. Eso incluye numérico 0, así como la cadena vacía ''y la matriz vacía []. En una ifdeclaración, la expresión se convierte explícitamente en boolean, por lo que if ( 0 )es lo mismo que if ( false ).
Al unir estas dos cosas, se obtiene un enigma: por un lado, como usted dice '0'es una cadena no vacía; Por otro lado, hemos dicho que puede usarse como un valor numérico 0, que está "vacío". PHP opta por tratar el "cero-ness" como más importante que el "stringiness", por lo que '0'se considera "falso".
En resumen: '0' == 0 == false; o(bool)'0' === (bool)(int)'0'
¿Alguien rechazó mi respuesta solo porque me atreví a defender PHP y a responder la pregunta con algo más que una broma barata e ignorante? ¿O hay algo inexacto o inútil en mi respuesta que les gustaría señalar?
IMSoP
1
Creo que PHP tomó esto de Perl, que tiene el mismo "0" comportamiento " es falso". En Perl, literalmente, no hay ninguna diferencia visible para el usuario entre la cadena "0"y el número 0: molesto al manejar JSON, pero muy intuitivo al manejar datos textuales. Entonces es imposible que el número 0sea falsey sin que también la cadena "0"sea falsey. PHP y JavaScript prestado esta decisión de diseño, además de añadir una cierta confusión al distinguir secuencias / Bools / tipos numéricos al tiempo que permite conversiones implícitas (PHP: 0 == "0 foo", 0 == false, pero "0 foo" == true: ==no es transitivo)
amon
@amon Sí, Perl adopta el enfoque interesante de (casi) todos los operadores y funciones integradas que obligan a los operandos a un tipo particular, con operadores adicionales como eqpara la igualdad de cadenas. Sin embargo, esto no lo salva de la no transitividad de los lanzamientos con pérdida: "0 foo"es cierto en un contexto booleano, pero es igual a 0bajo ==. Entonces, if ( ! $foo ) ..y $false = (1 == 2); if ( $foo == $false ) ... no den el mismo resultado. Supongo que al lenguaje le falta un operador de "igualdad booleana" que podría tratar esto consistentemente ...
IMSoP
Aunque "0" es 0 cuando se evalúa como numérico, cuando usamos una cadena en un contexto booleano (por ejemplo, en una instrucción if), no nos interesa su valor numérico. Si queremos interpretarlo como numérico, lo compararíamos con algún número, por ejemplo $_POST['id'] == 0, lo que deja en claro la intención de que queremos tratar la entrada del usuario como un número.
Michael Tsang
1
@MestreLion Ese ejemplo fue de Perl en lugar de PHP. La diferencia crucial es que no hay un tipo booleano separado en Perl, por lo que $falsetermina configurado en 0; así que cuando escribes $foo == $false, Perl no sabe que quieres una comparación booleana, y en su lugar convierte a int. En PHP, eso no sucede, porque $falsees booleano falso, por lo que se ==convierte en booleano, dando el mismo resultado que!
IMSoP
3
De acuerdo con la documentación de PHP en booleanos , dice que:
Al convertir a booleano, se consideran los siguientes valores FALSE
...
la cadena vacía y la cadena "0"
...
De otra manera:
Cualquier otro valor se considera VERDADERO (incluido cualquier recurso).
Si tu corres:
var_dump((bool)"0");
Imprimirá:
bool (falso)
Entonces está funcionando como se esperaba.
Para responder explícitamente a su pregunta:
Sin embargo, en la mayoría de los casos la conversión es innecesaria, ya que un valor se convertirá automáticamente si un operador, función o estructura de control requiere un argumento booleano.
Esto significa que el "autocast" de PHP convertirá "0" en un entero 0, que FALSEtambién se encuentra en una estructura de control como, por ejemplo, una if()declaración.
Me gustaría saber la razón de la decisión de diseño que trata "0" como FALSO cuando se convierte a booleano, en lugar de la necesidad de una conversión explícita.
'0'
se trata como0
en$x + 1
, ¿por qué no debería tratarse también como0
, y por lo tantofalse
, enif ( $x )
?Respuestas:
PHP fue diseñado (o, más bien, evolucionado) para su uso con solicitudes web, donde se trata con frecuencia de entrada de cadena (parámetros de URL o solicitudes POST de un formulario en un navegador). Como tal, automáticamente lanzará cadenas a otros tipos.
Un ejemplo simple de esto es que
'1' + '2'
da3
, no un error, o'12
', o alguna otra interpretación. Por la misma lógica, la cadena'0'
se puede usar como un número0
.Mientras tanto, como muchos lenguajes, PHP trata ciertos valores como "falsos" cuando se convierten en booleanos, que son intuitivamente "vacíos", como usted dice. Eso incluye numérico
0
, así como la cadena vacía''
y la matriz vacía[]
. En unaif
declaración, la expresión se convierte explícitamente en boolean, por lo queif ( 0 )
es lo mismo queif ( false )
.Al unir estas dos cosas, se obtiene un enigma: por un lado, como usted dice
'0'
es una cadena no vacía; Por otro lado, hemos dicho que puede usarse como un valor numérico0
, que está "vacío". PHP opta por tratar el "cero-ness" como más importante que el "stringiness", por lo que'0'
se considera "falso".En resumen:
'0' == 0 == false
; o(bool)'0' === (bool)(int)'0'
fuente
"0"
comportamiento " es falso". En Perl, literalmente, no hay ninguna diferencia visible para el usuario entre la cadena"0"
y el número0
: molesto al manejar JSON, pero muy intuitivo al manejar datos textuales. Entonces es imposible que el número0
sea falsey sin que también la cadena"0"
sea falsey. PHP y JavaScript prestado esta decisión de diseño, además de añadir una cierta confusión al distinguir secuencias / Bools / tipos numéricos al tiempo que permite conversiones implícitas (PHP:0 == "0 foo"
,0 == false
, pero"0 foo" == true
:==
no es transitivo)eq
para la igualdad de cadenas. Sin embargo, esto no lo salva de la no transitividad de los lanzamientos con pérdida:"0 foo"
es cierto en un contexto booleano, pero es igual a0
bajo==
. Entonces,if ( ! $foo ) ..
y$false = (1 == 2); if ( $foo == $false ) ...
no den el mismo resultado. Supongo que al lenguaje le falta un operador de "igualdad booleana" que podría tratar esto consistentemente ...$_POST['id'] == 0
, lo que deja en claro la intención de que queremos tratar la entrada del usuario como un número.$false
termina configurado en0
; así que cuando escribes$foo == $false
, Perl no sabe que quieres una comparación booleana, y en su lugar convierte a int. En PHP, eso no sucede, porque$false
es booleano falso, por lo que se==
convierte en booleano, dando el mismo resultado que!
De acuerdo con la documentación de PHP en booleanos , dice que:
De otra manera:
Si tu corres:
Imprimirá:
Entonces está funcionando como se esperaba.
Para responder explícitamente a su pregunta:
Esto significa que el "autocast" de PHP convertirá "0" en un entero 0, que
FALSE
también se encuentra en una estructura de control como, por ejemplo, unaif()
declaración.fuente