Operador PHP ternario corto (“Elvis”) vs operador coalescente nulo

10 minutos de lectura

avatar de usuario de balping
Balping

¿Alguien puede explicar las diferencias entre taquigrafía del operador ternario (?:) y operador coalescente nulo (??) en PHP?

¿Cuándo se comportan de manera diferente y cuándo de la misma manera (si eso sucede)?

$a ?: $b

VS.

$a ?? $b

  • Una buena manera de probarlo es usar una consola php en modo interactivo (php -a). Entonces ini_set('error_reporting', 'E_ALL')y ini_set('display_errors', 'on'). Entonces puedes intentar var_dump($var ?? 'default')) por ejemplo, y vea qué sucede si establece cualquier tipo de valores antes

    – St3an

    9 de julio de 2021 a las 13:55


  • No es fácil de encontrar a través de Google: documentación: Es posible omitir la parte media del operador ternario. Expresión expr1 ?: expr3 devoluciones expr1 si expr1 evalúa a truey expr3 de lo contrario.

    – Basj

    1 de diciembre de 2021 a las 14:07


Avatar de usuario de MasterOdin
maestroodin

Cuando su primer argumento es nulo, son básicamente iguales excepto que la fusión nula no generará un E_NOTICE cuando tienes una variable indefinida. El Documentos de migración de PHP 7.0 tiene esto que decir:

El operador coalescente nulo (??) se ha agregado como azúcar sintáctico para el caso común de necesitar usar un ternario junto con isset(). Devuelve su primer operando si existe y no es NULL; de lo contrario, devuelve su segundo operando.

Aquí hay un código de ejemplo para demostrar esto:

<?php

$a = null;

print $a ?? 'b'; // b
print "\n";

print $a ?: 'b'; // b
print "\n";

print $c ?? 'a'; // a
print "\n";

print $c ?: 'a'; // Notice: Undefined variable: c in /in/apAIb on line 14
print "\n";

$b = array('a' => null);

print $b['a'] ?? 'd'; // d
print "\n";

print $b['a'] ?: 'd'; // d
print "\n";

print $b['c'] ?? 'e'; // e
print "\n";

print $b['c'] ?: 'e'; // Notice: Undefined index: c in /in/apAIb on line 33
print "\n";

Las líneas que tienen el aviso son aquellas en las que estoy usando el operador ternario abreviado en lugar del operador coalescente nulo. Sin embargo, incluso con el aviso, PHP devolverá la misma respuesta.

Ejecuta el código: https://3v4l.org/McavC

Por supuesto, esto siempre es asumiendo que el primer argumento es null. Una vez que ya no es nulo, terminas con diferencias en que el ?? operador siempre devolvería el primer argumento mientras que el ?: taquigrafía solo lo haría si el primer argumento fuera verdadero, y eso depende de cómo PHP tipificaría las cosas a un valor booleano.

Entonces:

$a = false ?? 'f'; // false
$b = false ?: 'g'; // 'g'

entonces tendría $a ser igual a false y $b igual a 'g'.

  • Consejo: si ha estado usando ?? en lugar de ?: pero luego necesita hacer que su código sea compatible con versiones de PHP anteriores a la 7 (para un complemento, por ejemplo), entonces es posible que desee cambiar el ?? con isset($algo) ? $algo: $algo_más en todas partes de su código. Puede hacer esto fácilmente con Notepad++ o nedit (y otros editores también) usando la herramienta de buscar/reemplazar, seleccionando la opción de expresión regular e insertando en el campo de búsqueda: “\s*(\S+)\s*\?\?” y en el campo de reemplazo: ” isset($1) ? $1 :” sin las comillas (nedit usa \1 en lugar de $1). Luego reemplace todo.

    – Damián Verde

    8 de julio de 2017 a las 23:51

  • Esta es la respuesta correcta, sin embargo, la verificación de la veracidad es la principal diferencia y debe enfatizarse más.

    – Mancze

    1 de agosto de 2017 a las 12:37

  • @MasterOdin No satisfecho con su respuesta. Ambos no son iguales. Tener un resultado diferente.

    – Dhairya Lakhera

    18 de noviembre de 2017 a las 8:10

  • Vale la pena señalar que puedes usar ?? con encadenamiento. Por ejemplo: $b = []; var_dump($b['a']['b']['c'] ?? 'default'); o con objetos $b = new Foo; var_dump($b->a()->b()->c() ?? 'default');

    – Jack B.

    6 de noviembre de 2019 a las 14:59


  • Tenga en cuenta que el comportamiento también es diferente con $a = [];. Ver: 3v4l.org/iCCa0

    – Soullivaneuh

    4 de mayo de 2020 a las 14:36

avatar de usuario de a20
a20

Ejecuté lo siguiente en el modo interactivo de php (php -a en la terminal). El comentario en cada línea muestra el resultado.

var_export (false ?? 'value2');   // false
var_export (true  ?? 'value2');   // true
var_export (null  ?? 'value2');   // value2
var_export (''    ?? 'value2');   // ""
var_export (0     ?? 'value2');   // 0

var_export (false ?: 'value2');   // value2
var_export (true  ?: 'value2');   // true
var_export (null  ?: 'value2');   // value2
var_export (''    ?: 'value2');   // value2
var_export (0     ?: 'value2');   // value2

El operador coalescente nulo ??

  • ?? es como una “puerta” que solo deja pasar NULL.
  • Entonces, siempre devuelve el primer parámetroa menos que el primer parámetro pasa a ser NULL.
  • Esto significa ?? es igual que ( !isset() || is_null() )

Uso de ??

  • acortar !isset() || is_null() controlar
  • p.ej $object = $object ?? new objClassName();

Operador coalesce nulo de apilamiento

        $v = $x ?? $y ?? $z; 

        // This is a sequence of "SET && NOT NULL"s:

        if( $x  &&  !is_null($x) ){ 
            return $x; 
        } else if( $y && !is_null($y) ){ 
            return $y; 
        } else { 
            return $z; 
        }

El operador ternario ?:

  • ?: es como una puerta que deja anything falsy a través de – incluyendo NULL
  • Cualquier cosa falsa: 0, empty string, NULL, false, !isset(), empty()
  • Igual que el antiguo operador ternario: X ? Y : Z
  • Nota: ?: tirará PHP NOTICE en indefinido (unset o !isset()) variables

Uso de ?:

  • comprobación empty(), !isset(), is_null() etc.
  • acortar la operación ternaria como !empty($x) ? $x : $y a $x ?: $y
  • acortar if(!$x) { echo $x; } else { echo $y; } a echo $x ?: $y

Operador ternario de apilamiento

        echo 0 ?: 1 ?: 2 ?: 3; //1
        echo 1 ?: 0 ?: 3 ?: 2; //1
        echo 2 ?: 1 ?: 0 ?: 3; //2
        echo 3 ?: 2 ?: 1 ?: 0; //3
    
        echo 0 ?: 1 ?: 2 ?: 3; //1
        echo 0 ?: 0 ?: 2 ?: 3; //2
        echo 0 ?: 0 ?: 0 ?: 3; //3

    
        // Source & Credit: http://php.net/manual/en/language.operators.comparison.php#95997
   
        // This is basically a sequence of:

 
        if( truthy ) {}
        else if(truthy ) {}
        else if(truthy ) {}
        ..
        else {}

Apilando ambos, podemos acortar esto:

        if( isset($_GET['name']) && !is_null($_GET['name'])) {
            $name = $_GET['name'];
        } else if( !empty($user_name) ) {
             $name = $user_name; 
        } else {
            $name="anonymous";
        }

A esto:

        $name = $_GET['name'] ?? $user_name ?: 'anonymous';

¿Guay, verdad? 🙂

  • Superior, excepto por un error: acortar if(!$x) { echo $x; } else { echo $y; } a echo $x ?: $y. Uno no es igual al otro. La condición tiene que ser if($x) en cambio, sin negación. Todavía me ha permitido aprender un poco sobre este operador que era nuevo para mí en su versión corta, por lo que la publicación recibió un voto a favor.

    – Saqueador de almas

    25 de noviembre de 2020 a las 12:13

  • En php, utilice siempre elseif como una sola palabra para alinearse con los estándares de codificación PSR-12. Sé que solo estabas haciendo una demostración, pero isset($_GET['name']) && !is_null($_GET['name']) en primer lugar es la verificación redundante.

    – mickmackusa

    25 de diciembre de 2020 a las 7:40


  • Esta es una muy buena respuesta para aprender cómo funcionan estos operadores, ¡pero espero nunca tener que solucionar problemas con el código de producción que usa ambos operadores en una declaración!

    – Liam

    12 mayo 2021 a las 19:18

Avatar de usuario de Andrew
Andrés

Si usa el operador ternario abreviado de esta manera, generará un aviso si $_GET['username'] no está configurado:

$val = $_GET['username'] ?: 'default';

Así que en su lugar tienes que hacer algo como esto:

$val = isset($_GET['username']) ? $_GET['username'] : 'default';

El operador coalescente nulo es equivalente a la declaración anterior, y devolverá ‘predeterminado’ si $_GET['username'] no está configurado o está null:

$val = $_GET['username'] ?? 'default';

Tenga en cuenta que no comprueba la veracidad. Comprueba solo si está establecido y no es nulo.

También puedes hacer esto, y lo primero definido (establecido y no null) se devolverá el valor:

$val = $input1 ?? $input2 ?? $input3 ?? 'default';

Ahora que es un operador coalescente adecuado.

  • Para que no se genere un aviso, se debe utilizar $var = empty($other_var) ? 'default_value' : $other_var;. Tenga en cuenta que esto excluye '', null, falsey 0

    – St3an

    9 de julio de 2021 a las 13:50

Avatar de usuario de Dhairya Lakhera
Dhairya Lakhera

La gran diferencia es que

  1. Operador Ternario expresión expr1 ?: expr3 devoluciones expr1 si expr1 evalúa a
    TRUE pero en la otra mano Operador coalescente nulo expresión (expr1) ?? (expr2)
    evalúa a expr1 si expr1 es no NULL

  2. Operador Ternario expr1 ?: expr3 emitir un aviso si el valor del lado izquierdo (expr1) no existe pero por otro lado Operador coalescente nulo (expr1) ?? (expr2) En particular, no emite un aviso si el valor del lado izquierdo (expr1) no existe, al igual que isset().

  3. Operador Ternario se deja asociativo

    ((true ? 'true' : false) ? 't' : 'f');
    

    Operador coalescente nulo es asociativo correcto

    ($a ?? ($b ?? $c));
    

Ahora vamos a explicar la diferencia entre por ejemplo:

Operador Ternario (?:)

$x='';
$value=($x)?:'default';
var_dump($value);

// The above is identical to this if/else statement
if($x){
  $value=$x;
}
else{
  $value="default";
}
var_dump($value);

Operador coalescente nulo (??)

$value=($x)??'default';
var_dump($value);

// The above is identical to this if/else statement
if(isset($x)){
  $value=$x;
}
else{
  $value="default";
}
var_dump($value);

Aquí está la tabla que explica la diferencia y similitud entre '??' y ?:

ingrese la descripción de la imagen aquí

Nota especial: el operador coalescente nulo y el operador ternario es una expresión, y no se evalúa como una variable, sino como el resultado de una expresión. Es importante saber esto si desea devolver una variable por referencia. La instrucción devuelve $foo ?? $barra; y devolver $var == 42? $a : $b; en una función de devolución por referencia, por lo tanto, no funcionará y se emitirá una advertencia.

Avatar de usuario de Chazy Chaz
chazy chaz

Ambos se comportan de manera diferente cuando se trata del manejo dinámico de datos.

Si la variable está vacía ( ” ), la fusión nula tratará la variable como verdadera, pero el operador ternario abreviado no lo hará. Y eso es algo a tener en cuenta.

$a = NULL;
$c="";

print $a ?? '1b';
print "\n";

print $a ?: '2b';
print "\n";

print $c ?? '1d';
print "\n";

print $c ?: '2d';
print "\n";

print $e ?? '1f';
print "\n";

print $e ?: '2f';

Y la salida:

1b
2b

2d
1f

Notice: Undefined variable: e in /in/ZBAa1 on line 21
2f

Enlace: https://3v4l.org/ZBAa1

  • Esto es claramente contrario a la intuición de PHP, donde una cadena vacía generalmente se considera falsa. Sin embargo, está claramente indicado en los documentos para ??: It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.

    – Simón

    17 oct 2019 a las 13:06


avatar de usuario de hatef
odio

Ambos son abreviaturas de expresiones más largas.

?: es corto para $a ? $a : $b. Esta expresión se evaluará como $a si $a se evalúa como VERDADERO.

?? es corto para isset($a) ? $a : $b. Esta expresión se evaluará como $a si se establece $a y no es nulo.

Sus casos de uso se superponen cuando $a no está definido o es nulo. Cuando $a no está definido ?? no producirá un E_NOTICE, pero los resultados son los mismos. Cuando $a es nulo, el resultado es el mismo.

  • Esto es claramente contrario a la intuición de PHP, donde una cadena vacía generalmente se considera falsa. Sin embargo, está claramente indicado en los documentos para ??: It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.

    – Simón

    17 oct 2019 a las 13:06


Para los principiantes:

Operador coalescente nulo (??)

Todo es verdad excepto null valores e indefinidos (variable/índice de matriz/atributos de objeto)

ex:

$array = [];
$object = new stdClass();

var_export (false ?? 'second');                           # false
var_export (true  ?? 'second');                           # true
var_export (null  ?? 'second');                           # 'second'
var_export (''    ?? 'second');                           # ""
var_export ('some text'    ?? 'second');                  # "some text"
var_export (0     ?? 'second');                           # 0
var_export ($undefinedVarible ?? 'second');               # "second"
var_export ($array['undefined_index'] ?? 'second');       # "second"
var_export ($object->undefinedAttribute ?? 'second');     # "second"

esto es básicamente verificar que la variable (índice de matriz, atributo de objeto, etc.) exista y no null. Similar a isset función

Taquigrafía del operador ternario (?:)

todas las cosas falsas (false,null,0,cadena vacía) vienen como falsos, pero si es indefinido también vienen como falsos pero Notice tirará

ex

$array = [];
$object = new stdClass();

var_export (false ?: 'second');                           # "second"
var_export (true  ?: 'second');                           # true
var_export (null  ?: 'second');                           # "second"
var_export (''    ?: 'second');                           # "second"
var_export ('some text'    ?? 'second');                  # "some text"
var_export (0     ?: 'second');                           # "second"
var_export ($undefinedVarible ?: 'second');               # "second" Notice: Undefined variable: ..
var_export ($array['undefined_index'] ?: 'second');       # "second" Notice: Undefined index: ..
var_export ($object->undefinedAttribute ?: 'second');     # "Notice: Undefined index: ..

Espero que esto ayude

¿Ha sido útil esta solución?