web-dev-qa-db-fra.com

PHP opérateur ternaire vs opérateur null coalescent

Quelqu'un peut-il expliquer les différences entre l'opérateur abrégé de l'opérateur ternaire (?:) et l'opérateur de fusion nul (??) en PHP?

Quand se comportent-ils différemment et quand de la même manière (si cela se produit même)?

$a ?: $b

VS.

$a ?? $b
205
balping

Lorsque votre premier argument est null, il est pratiquement identique, sauf que la fusion nulle ne génère pas E_NOTICE lorsque vous avez une variable non définie. Le PHP 7.0 Docs de migration a ceci à dire:

L'opérateur de coalescence nul (??) a été ajouté en tant que sucre syntaxique pour le cas courant de devoir utiliser un ternaire en conjonction avec isset (). Il retourne son premier opérande s'il existe et n'est pas NULL; sinon, il retourne son deuxième opérande.

Voici un exemple de code pour illustrer ceci:

<?php

$a = null;

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

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

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

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

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

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

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

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

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

Et c'est la sortie:

b
b
a

Notice: Undefined variable: c in /in/apAIb on line 14
a
d
d
e

Notice: Undefined index: c in /in/apAIb on line 33
e

Les lignes qui ont la notification sont celles où j'utilise l'opérateur ternaire abrégé, par opposition à l'opérateur de coalescence nul. Cependant, même avec la notification, PHP donnera la même réponse.

Exécutez le code: https://3v4l.org/McavC

Bien sûr, cela suppose toujours que le premier argument est null. Une fois que ce n'est plus nul, vous vous retrouvez avec des différences en ce sens que l'opérateur ?? renverra toujours le premier argument, alors que le raccourci ?: ne le ferait que si le premier argument était véridique, et cela dépend de la manière dont PHP taperait -diffuser les choses à un booléen .

Alors:

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

$a serait alors égal à false et $b égal à 'g'.

213
MasterOdin

Si vous utilisez l'opérateur de raccourci ternaire comme ceci, un avis sera émis si $_GET['username'] n'est pas défini:

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

Au lieu de cela, vous devez faire quelque chose comme ceci:

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

L'opérateur null coalescing est équivalent à l'instruction ci-dessus et renvoie «par défaut» si $_GET['username'] n'est pas défini ou est null:

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

Notez que il ne vérifie pas la véracité . Il vérifie uniquement s'il est défini et non nul.

Vous pouvez également le faire, et la première valeur définie (définie et non null) sera renvoyée:

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

Maintenant, c’est un bon opérateur de coalescence.

57
Andrew

La principale différence est que 

  1. Ternary Operator expression expr1 ?: expr3 renvoie expr1 si expr1 est évalué à TRUE mais d'autre part Null Opérateur Coalescing expression (expr1) ?? (expr2).__ est évalué à expr1 si expr1 est pasNULL

  2. Ternary L'opérateurexpr1 ?: expr3 émet un avis si le côté gauche Valeur (expr1) n'existe pas mais par contre Null Coalescing Operator(expr1) ?? (expr2) En particulier, n'émet pas d'avis si le La valeur de côté gauche (expr1) n'existe pas, tout comme isset()

  3. TernaryOperator reste associatif 

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

    L'opérateur de coalescence nul est juste associatif 

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

Maintenant, expliquons la différence entre par exemple: 

Opérateur ternaire(?:) 

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

Opérateur de coalescence nul(??)

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

Voici le tableau qui explique la différence et la similarité entre '??' et ?: 

 enter image description here

Remarque spéciale: l'opérateur de coalescence nul et l'opérateur ternaire est un expression, et qu'il n'évalue pas à une variable, mais à la résultat d'une expression. C'est important de savoir si vous voulez retourne une variable par référence. La déclaration retourne $ foo ?? $ bar; et retourne $ var == 42? $ a: $ b; dans une fonction de renvoi par référence sera donc pas de travail et un avertissement est émis.

33
Dhairya Lakhera

Ran le ci-dessous sur le mode interactif php (php -a sur le terminal). Le commentaire sur chaque ligne montre le résultat.

var_dump (false ?? 'value2');   # bool(false)
var_dump (true  ?? 'value2');   # bool(true)
var_dump (null  ?? 'value2');   # string(6) "value2"
var_dump (''    ?? 'value2');   # string(0) ""
var_dump (0     ?? 'value2');   # int(0)

var_dump (false ?: 'value2');   # string(6) "value2"
var_dump (true  ?: 'value2');   # bool(true)
var_dump (null  ?: 'value2');   # string(6) "value2"
var_dump (''    ?: 'value2');   # string(6) "value2"
var_dump (0     ?: 'value2');   # string(6) "value2"

Voici donc mon interprétation:

1. L'opérateur de coalescence nul - ??:

  • ?? est comme une "porte" qui ne laisse que NULL à travers
  • Donc, il retourne toujours le premier paramètre, sauf si le premier paramètre est NULL
  • Cela signifie que ?? est identique à ( !isset() || is_null() )

2. L’opérateur ternaire - ?:

  • ?: EST COMME UNE PORTE QUI LAISSE anything falsy TRAVERSER - Y COMPRIS NULL
  • 0, empty string, NULL, false, !isset(), empty() .. tout ce qui sent la fausseté 
  • Comme l'opérateur ternaire classique: echo ($x ? $x : false) 
  • REMARQUE: ?: jettera PHP NOTICE sur des variables non définies (unset ou !isset())

3. Alors docteur, quand dois-je utiliser ?? et ?: ..

  • Je ne fais que plaisanter - je ne suis pas médecin et ce n'est qu'une interprétation 
  • Je voudrais utiliser ?: quand
    • faire des vérifications empty($x)
    • L'opération ternaire classique comme !empty($x) ? $x : $y peut être réduite à $x ?: $y 
    • if(!$x) { fn($x); } else { fn($y); } peut être raccourci à fn(($x ?: $y)) 
  • Je voudrais utiliser ?? quand
    • Je veux faire un chèque !isset() || is_null() 
    • par exemple, vérifiez si un objet existe - $object = $object ?? new objClassName();

4. Opérateurs empilant ...

  1. L'opérateur ternaire peut être empilé ... 

    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 et crédit pour ce code

    Ceci est essentiellement une séquence de:

    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
    
  2. Null Coalese Operator peut être empilé ... 

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

    Ceci est une séquence de:

    if(!isset($x) || is_null($x) ) {} 
    else if(!isset($y) || is_null($y) ) {}
    else {}
    
  3. En utilisant l'empilement, je peux raccourcir ceci:

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

    Pour ça:

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

    Cool, non? :-)

27
a20

Les deux se comportent différemment en matière de traitement dynamique des données.

Si la variable est vide (''), la fusion nulle traitera la variable comme vraie, mais l'opérateur ternaire abrégé ne le fera pas. Et c'est quelque chose à avoir à l'esprit.

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

Et la sortie:

1b
2b

2d
1f

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

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

12
Chazy Chaz

Les deux sont des raccourcis pour des expressions plus longues.

?: est l'abréviation de $a ? $a : $b. Cette expression sera évaluée à $ a si $ a est évaluée àTRUE.

?? est l'abréviation de isset($a) ? $a : $b. Cette expression sera évaluée à $ a si $ a est défini et non nul.

Leurs cas d'utilisation se chevauchent lorsque $ a n'est pas défini ou est nul. Lorsque $ a n'est pas défini, ?? ne produira pas de E_NOTICE, mais les résultats sont identiques. Lorsque $ a est nul, le résultat est le même.

7
Dean Or

Pour les débutants:

Opérateur de coalescence nul (??)

Tout est vrai sauf null valeurs et indéfini (attributs de variable/tableau/d'objet)

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"

il s’agit en gros de vérifier que la variable (index de tableau, attribut d’objet, etc.) est existante et non pas null. semblable à la fonction isset

sténographie de l'opérateur ternaire (?:)

toutes les fausses choses (false, null, 0, chaîne vide) sont fournies comme fausses, mais si c'est un indéfini, elles deviennent également fausses, mais Notice jette

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: ..

J'espère que cela t'aides

4
Supun Praneeth

Faites défiler vers le bas this link et affichez la section. Elle vous donne un exemple comparatif, comme indiqué ci-dessous:

<?php
/** Fetches the value of $_GET['user'] and returns 'nobody' if it does not exist. **/
$username = $_GET['user'] ?? 'nobody';
/** This is equivalent to: **/
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

/** Coalescing can be chained: this will return the first defined value out of $_GET['user'], $_POST['user'], and 'nobody'. **/
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

Cependant, il n'est pas conseillé de chaîner les opérateurs car cela rend plus difficile la compréhension du code lors de sa lecture ultérieure.

L'opérateur de coalescence nul (??) a été ajouté en tant que sucre syntaxique pour le cas courant où il est nécessaire d'utiliser un ternaire conjointement avec isset (). Il retourne son premier opérande s'il existe et n'est pas NULL; sinon, il retourne son deuxième opérande.

Essentiellement, l’utilisation de l’opérateur coalescent rendra la vérification automatique nulle, contrairement à l’opérateur ternaire.

3
Script47

Il semble qu'il y ait des avantages et des inconvénients à utiliser soit ??, soit ?:. Le pro à utiliser ?: est qu’il évalue false et null et "" les mêmes. L'inconvénient est qu'il signale un E_NOTICE si l'argument précédent est null. Avec ??, le pro, c’est qu’il n’ya pas de E_NOTICE, mais l’inconvénient est qu’il n’évalue pas false et a la même valeur. D'après mon expérience, des personnes ont commencé à utiliser les termes null et false de manière interchangeable, mais elles ont fini par modifier leur code afin de les rendre compatibles avec l'utilisation de null ou de false, mais pas des deux. Une alternative consiste à créer une condition ternaire plus élaborée: (isset($something) or !$something) ? $something : $something_else.

Voici un exemple de différence entre l'opérateur ?? qui utilise les valeurs null et false: 

$false = null;
$var = $false ?? "true";
echo $var . "---<br>";//returns: true---

$false = false;
$var = $false ?? "true";
echo $var . "---<br>"; //returns: ---

En élaborant sur l'opérateur ternaire, nous pouvons toutefois faire en sorte qu'une chaîne "" vide se comporte comme s'il s'agissait d'un caractère nul sans envoyer d'e-notot:

$false = null;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = false;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = "";
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = true;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: 1---

Personnellement, je pense que ce serait vraiment bien si une future version de PHP incluait un autre nouvel opérateur: :? qui remplaçait la syntaxe ci-dessus. C'est-à-dire: // $var = $false :? "true"; Cette syntaxe évaluerait nullement, "false" et "" de la même manière et ne lancerait pas un E_NOTICE ...

3
Damian Green

Les autres réponses vont en profondeur et donnent de bonnes explications. Pour ceux qui cherchent une réponse rapide,

$a ?: 'fallback' est $a ? $a : 'fallback'

tandis que

$a ?? 'fallback' est $a = isset($a) ? $a : 'fallback'


La principale différence serait que l'opérateur de gauche est:

  • Une valeur de fausseté qui n'est PAS nulle (0, '', false, [], ...)
  • Une variable non définie
1
Yaron U.
class a
{
    public $a = 'aaa';
}

$a = new a();

echo $a->a;  // Writes 'aaa'
echo $a->b;  // Notice: Undefined property: a::$b

echo $a->a ?? '$a->a does not exists';  // Writes 'aaa'

// Does not throw an error although $a->b does not exist.
echo $a->b ?? '$a->b does not exist.';  // Writes $a->b does not exist.

// Does not throw an error although $a->b and also $a->b->c does not exist.
echo $a->b->c ?? '$a->b->c does not exist.';  // Writes $a->b->c does not exist.
1
Čamo

Null Coalescing operator n'effectue que deux tâches: il vérifie whether the variable is set et whether it is null. Regardez l'exemple suivant:

<?php
# case 1:
$greeting = 'Hola';
echo $greeting ?? 'Hi There'; # outputs: 'Hola'

# case 2:
$greeting = null;
echo $greeting ?? 'Hi There'; # outputs: 'Hi There'

# case 3:
unset($greeting);
echo $greeting ?? 'Hi There'; # outputs: 'Hi There'

L'exemple de code ci-dessus indique que Null Coalescing operator traite une variable non existante et une variable définie sur NULL de la même manière.

Null Coalescing operator est une amélioration par rapport au ternary operator. Jetez un coup d'oeil à l'extrait de code suivant comparant les deux:

<?php /* example: checking for the $_POST field that goes by the name of 'fullname'*/
# in ternary operator
echo "Welcome ", (isset($_POST['fullname']) && !is_null($_POST['fullname']) ? $_POST['fullname'] : 'Mr. Whosoever.'); # outputs: Welcome Mr. Whosoever.
# in null coalecing operator
echo "Welcome ", ($_POST['fullname'] ?? 'Mr. Whosoever.'); # outputs: Welcome Mr. Whosoever.

La différence entre les deux réside donc dans le fait que l'opérateur Null Coalescing operator est conçu pour gérer des variables non définies mieux que le ternary operator. Considérant que, le ternary operator est un raccourci pour if-else.

Null Coalescing operator n'est pas destiné à remplacer ternary operator, mais dans certains cas d'utilisation, comme dans l'exemple ci-dessus, il vous permet d'écrire du code en clair avec moins de tracas.

Crédits: http://dwellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples

0
Pranav Rana

Lorsque vous utilisez des superglobales telles que $ _GET ou $ _REQUEST, vous devez être conscient du fait qu’elles peuvent être une chaîne vide .

$username = $_GET['user'] ?? 'nobody';

échouera car la valeur de $ username est maintenant une chaîne vide.

Ainsi, lorsque vous utilisez $ _GET ou même $ _REQUEST, vous devez utiliser l'opérateur ternaire à la place:

$username = (!empty($_GET['user'])?$_GET['user']:'nobody';

Maintenant, la valeur de $ username est "personne" comme prévu.

0
Alexander Behling