PHP es famoso por su malabarismo de tipos. Debo admitir que me desconcierta, y estoy teniendo dificultades para descubrir cosas lógicas / fundamentales básicas en las comparaciones.
Por ejemplo: si $a > $b
es verdadero y $b > $c
es verdadero, ¿debe significar que siempre$a > $c
es verdad también?
Siguiendo la lógica básica, diría que sí. pero estoy tan desconcertado de que no confío realmente en PHP en esto. ¿Quizás alguien pueda dar un ejemplo en el que este no sea el caso?
También me pregunto con los operadores estrictos menor que y estricto mayor que (ya que su significado se describe como estrictamente que solo sabía en el pasado por las comparaciones de igualdad) si hay alguna diferencia si los operandos izquierdo y derecho se intercambian con valores estrictamente desiguales:
# Precondition:
if ($a === $b) {
throw new Exception(
'Both are strictly equal - can not compare strictly for greater or smaller'
);
}
($a > $b) !== ($b > $a)
Para la mayoría de las combinaciones de comparación de tipos, estos operadores de comparación mayor / menor no están documentados, por lo que leer el manual no fue realmente útil en este caso.
fuente
($a > $b) !== ($b < $a)
?Respuestas:
Los operadores de comparación de PHP se desvían de las definiciones informáticas científicas de varias formas:
Para constituir una relación de equivalencia
==
tiene que ser reflexiva, simétrica y transitiva:El
==
operador de PHP no es reflexivo ,$a == $a
es decir, no siempre es cierto:Nota: El hecho de que cualquier comparación que involucre
NAN
siemprefalse
no es específico de PHP. Es un mandato del estándar IEEE 754 para aritmética de punto flotante ( más información ).El
==
operador de PHP es simétrico , es decir,$a == $b
y$b == $a
son siempre iguales.PHP
==
operador es no transitiva , es decir, desde$a == $b
y$b == $c
qué no sigue$a == $c
:Para constituir un orden parcial
<=
/>=
tiene que ser reflexivo, antisimétrico y transitivo:El
<=
operador de PHP no es reflexivo ,$a <= $a
es decir, no siempre es cierto (el ejemplo es el mismo que para==
).El
<=
operador de PHP no es anti-simétrico , es decir, de$a <= $b
y$b <= $a
no sigue$a == $b
:El
<=
operador de PHP no es transitivo , es decir, de$a <= $b
y$b <= $c
no sigue$a <= $c
(el mismo ejemplo que para==
).Extra: el
<=
operador de PHP no es total , es decir, ambos$a <= $b
y$b <= $a
puede ser falso:Para constituir un orden parcial estricto
<
/>
tiene que ser irreflexivo, asimétrico y transitivo:El
<
operador de PHP es irreflexivo ,$a < $a
es decir, nunca es cierto. Tenga en cuenta que esto es cierto solo a partir de PHP 5.4 .INF < INF
Evaluado previamente atrue
.El
<
operador de PHP no es asimétrico , es decir, de$a < $b
no sigue!($b < $a)
(ejemplo igual que para<=
no ser antisimétrico).El
<
operador de PHP no es transitivo , es decir, de$a < $b
y$b < $c
no sigue$a < $c
:Extra: El
<
operador de PHP no es tricotómico , es decir, todo$a < $b
,$b < $a
y$a == $b
puede ser falso (Ejemplo igual que para<=
no ser total).Extra: el
<
operador de PHP puede ser circular , es decir, es posible que$a < $b
,$b < $c
y$c < $a
:Nota: El ejemplo anterior arroja un aviso de "Objeto de clase stdClass no se pudo convertir en doble".
Puede encontrar algunos buenos gráficos para los operadores de comparación de PHP en PHP Sadness 52 - Operadores de comparación .
Como última nota, quiero señalar que hay dos igualdades que hace PHP garantía (a diferencia de casi todo lo demás). Estos dos siempre se mantienen, simplemente porque el compilador reduce uno al otro:
fuente
($a > $b) and ($b > $c)
con$a > $c
aunque la documentación dice que esos operadores<
/>
dicen que son estrictos ?$a == $b
es lo mismo que(type) $a === (type) $b
. Un simple ejemplo de esto es eso"15" == "0xf"
, pero(int) "15" !== (int) "0xf"
. Y tanto la comparación como las reglas de conversión en PHP son totalmente locas ^^(int)"0xf"
evalúa a un número entero0
, por supuesto0 !== 15
. La comparación en este ejemplo se comporta exactamente como se esperaba. Es el casting lo que confunde aquí. Lo admito,(INF < INF) === true
fue un problema de comparación genuino, pero fue un caso especial, y se resolvió como usted señaló. Excelente respuesta ... +1No hay operadores de comparación estrictamente idénticos (
>==
o<==
) en PHP (por PHP 5.6.14 al menos) , pero hay algunas formas de hacer cumplir una verificación de tipo estricta antes de marcar Mayor / Inferior:if (gettype($a) === gettype($b))
if ((string)$a === (string)$b)
if (($a . '') === ($b . ''))
Toma nota de que:
INF
yNAN
son de tipofloat
bajoieee754e
es siempre de tipofloat
y nunca,integer
incluso si el número es pequeñoPHP_INT_MAX
se convierten automáticamente enfloat
INF
valorNULL
0
se convierten de octal a decimal (por convención)0
a un número entero elimina el encabezado0
Lista de algunas comparaciones exóticas:
Igual pero no idéntico:
¿Más bajo y más grande al mismo tiempo?
Igual e idéntico:
Menor o mayor:
$a > $b > $c
Enigma cuando:$a
no es mayor que$c
.Divertida comparación de cuerdas: 'Queen'
>
'King'>
'Jack'>
'Ace'Consulte también las tablas de comparación de tipos de PHP que cubren pares:
isset()
yis_null()
if()
yempty()
==
vs.===
Compruebe las diferencias entre las versiones de PHP en vivo en. http://3v4l.org/MAfDu .
fuente
if ( (string)$a===(string)$b )
pero ¿no es exactamente lo mismo queif ( (string)$a==(string)$b )
?(string)1==(string)'01'
->bool(true)
y type-juggle(1 . '')=='01'
->bool(true)
no es exactamente lo mismo que===
cuando obtendríabool(false)
ambas cuentasINFINITY is equal to INFINITY which is mathematically incorrect!
es una declaración decididamente discutible. También tenga en cuenta queNaN
es por convención no mayor, menor o igual a cualquier cosa en cualquier lenguaje de programación que yo sepa.Después de corregir la segunda parte de su pregunta, dejo la respuesta a esa parte a los demás. Solo quiero dar la respuesta más sorprendente a la primera parte de su pregunta, es decir, si hay un ejemplo de que los operadores
<
y>
son intransitivos. Aquí está.Estos son todos
true
:Si
<
fuera transitivo ($a < $b
∧$b < $c
⇒$a < $c
), la última línea seríapero PHP intenta ser amable (?!) e interpretar cadenas como números siempre que puede.
Resulta que, debido a la intransibilidad anterior, se
sort()
pueden clasificar los mismos elementos en un orden diferente dependiendo de su orden de entrada, incluso cuando no hay dos elementos==
(y ningún elemento es NAN). Señalé esto en un comentario para sort () , cuya esencia es:fuente
sort()
tabla nueva , la elegí también por las implicaciones prácticas al escribir la publicación de blog relacionada The Greatest PHP Value . Gracias de nuevo por su respuesta.usort
siempre que sea posible?usort($arr, 'strcmp')
. Esto funciona (para cadenas, por supuesto), pero es mejor usarlosort($arr, SORT_STRING)
.