¿Quién es Elvis y qué tiene que ver con PHP?
\n\nSi alguna vez has escrito en PHP, seguramente has visto construcciones extrañas en código ajeno: $name ?: 'Invitado' o $name ?? 'Invitado'. A simple vista, parecen lo mismo. Pero en realidad, detrás de estos dos operadores se esconden mecánicas completamente diferentes que pueden tanto salvar tu código como meterte en problemas.
En Stack Overflow, la pregunta "Operador short-ternary ("Elvis") de PHP vs operador null coalescing" ha acumulado decenas de miles de visitas. Y no es casualidad. Los desarrolladores se confunden, cometen errores y luego pasan mucho tiempo buscando bugs. Aclaremos de una vez por todas quién es quién y dejemos de adivinar.
\n\nEn este artículo no solo enumeraremos las diferencias. Echaremos un vistazo bajo el capó de PHP, veremos casos reales de producción y entenderemos cuándo usar cada operador. ¡Allá vamos!
\n\nBreve introducción: ¿qué son exactamente?
\n\nOperador ternario (clásico)
\nPara empezar, recordemos lo básico. El operador ternario es una forma abreviada de if-else:
\n\n$age = 20;\n$status = ($age >= 18) ? 'Adulto' : 'Niño';\n// $status = 'Adulto'\n\nSimple: si la condición es verdadera, tomamos el primer valor; de lo contrario, el segundo.
\n\nShort-ternary (también conocido como operador Elvis) — ?:
\nEs una abreviatura para cuando verificas si una variable es "verdadera" y quieres usar su propio valor:
\n\n$name = 'Alex';\n$greeting = $name ?: 'Invitado';\n// $greeting = 'Alex'\n\n$name = '';\n$greeting = $name ?: 'Invitado';\n// $greeting = 'Invitado'\n\nFunciona así: si $name se evalúa como true, tomamos $name. De lo contrario, "Invitado".
Operador null coalescing — ??
\nApareció en PHP 7.0 y rápidamente se convirtió en el favorito de los desarrolladores:
\n\n$name = 'Alex';\n$greeting = $name ?? 'Invitado';\n// $greeting = 'Alex'\n\n$name = null;\n$greeting = $name ?? 'Invitado';\n// $greeting = 'Invitado'\n\nDiferencia con Elvis: la verificación es solo contra null, no contra "falsedad" en general.
\n\nLa diferencia principal: ¿qué se considera "vacío"?
\n\nAquí es donde se pone interesante. Veamos una tabla comparativa para diferentes valores de $value:
$value = false;\necho $value ?: 'default'; // 'default' (false es "falso")\necho $value ?? 'default'; // false (false NO es null)\n\n$value = 0;\necho $value ?: 'default'; // 'default' (0 es "falso")\necho $value ?? 'default'; // 0 (0 NO es null)\n\n$value = '';\necho $value ?: 'default'; // 'default' (cadena vacía es "falso")\necho $value ?? 'default'; // '' (cadena vacía NO es null)\n\n$value = [];\necho $value ?: 'default'; // 'default' (array vacío es "falso")\necho $value ?? 'default'; // [] (array vacío NO es null)\n\n$value = '0';\necho $value ?: 'default'; // 'default' (cadena "0" es "falso"!)\necho $value ?? 'default'; // '0' (cadena "0" NO es null)\n\n¿Ves la diferencia? Elvis funciona como una verificación de "veracidad" (truthy/falsy), mientras que null coalescing es una verificación estricta de existencia y diferencia de null.
\n\nBajo el capó: cómo funciona a nivel del motor
\n\nEchemos un vistazo al código fuente de PHP (bueno, casi). Si alguna vez has compilado PHP desde el código fuente, sabrás que ambos operadores se procesan en la etapa de análisis sintáctico.
\n\nShort-ternary (?):
\nEn realidad, es azúcar sintáctico. $a ?: $b se convierte en $a ? $a : $b. Pero hay un detalle: PHP no evalúa $a dos veces. Guarda el resultado en una variable temporal. Esto es importante para funciones con efectos secundarios:
function getData() {\n echo "¡Función llamada!\\n";\n return rand(0, 1) ? 'data' : '';\n}\n\n// Elvis llama a la función UNA vez\n$result = getData() ?: 'default';\n// "¡Función llamada!" — una vez\n\nSi PHP evaluara $a dos veces,