Ternärer PHP-Operator gegen Null-Koaleszenz-Operator

341

Kann jemand die Unterschiede zwischen dem ternären Operator shorthand ( ?:) und dem Null-Coalescing-Operator ( ??) in PHP erklären ?

Wann verhalten sie sich anders und wann auf die gleiche Weise (wenn das überhaupt passiert)?

$a ?: $b

VS.

$a ?? $b
balping
quelle

Antworten:

343

Wenn Ihr erstes Argument null ist, sind sie im Grunde gleich, außer dass die Null-Koaleszenz keine ausgibt, E_NOTICEwenn Sie eine undefinierte Variable haben. In den PHP 7.0-Migrationsdokumenten heißt es:

Der Null-Koaleszenz-Operator (??) wurde als syntaktischer Zucker für den allgemeinen Fall hinzugefügt, dass in Verbindung mit isset () ein Ternär verwendet werden muss. Es gibt seinen ersten Operanden zurück, wenn er existiert und nicht NULL ist. Andernfalls wird der zweite Operand zurückgegeben.

Hier ist ein Beispielcode, um dies zu demonstrieren:

<?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";

Die Zeilen mit dem Hinweis sind diejenigen, in denen ich den ternären Kurzoperator im Gegensatz zum Null-Koaleszenzoperator verwende. Trotz des Hinweises gibt PHP die gleiche Antwort zurück.

Führen Sie den Code aus: https://3v4l.org/McavC

Dies setzt natürlich immer das erste Argument voraus null. Sobald es nicht mehr null ist, gibt es Unterschiede darin, dass der ??Operator immer ?:das erste Argument zurückgibt, während die Kurzform nur dann, wenn das erste Argument wahr ist, und dies davon abhängt, wie PHP Dinge in einen Booleschen Wert umwandelt .

Damit:

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

wäre dann $agleich falseund $bgleich 'g'.

MasterOdin
quelle
8
Tipp: Wenn Sie verwendet haben? statt ?: aber dann müssen Sie Ihren Code mit PHP-Versionen älter als 7 kompatibel machen (zum Beispiel für ein Plugin), dann möchten Sie vielleicht das ?? mit isset ($ etwas)? $ Something: $ Something_else überall in Ihrem Code. Sie können dies problemlos mit Notepad ++ oder nedit (und anderen Editoren) tun, indem Sie das Tool zum Suchen / Ersetzen verwenden, die Option für reguläre Ausdrücke auswählen und in das Suchfeld einfügen: "\ s * (\ S +) \ s * \? \?" und im Ersetzungsfeld: "isset ($ 1)? $ 1:" ohne Anführungszeichen (nedit verwendet \ 1 anstelle von $ 1). Dann alle ersetzen.
Damian Green
14
Dies ist die richtige Antwort, jedoch ist die Überprüfung der Wahrhaftigkeit der Hauptunterschied und sollte stärker betont werden.
Mancze
2
@ MasterOdin Nicht zufrieden mit Ihrer Antwort. Beide sind nicht gleich. Haben Sie ein anderes Ergebnis.
Neugierig
1
Es ist erwähnenswert, dass Sie verwenden können? mit Verkettung. Zum Beispiel: $b = []; var_dump($b['a']['b']['c'] ?? 'default');oder mit Objekten$b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
Jack B
Bitte beachten Sie, dass das Verhalten auch bei anders ist $a = [];. Siehe: 3v4l.org/iCCa0
Soullivaneuh
75

Lief das unten im PHP Interactive Mode ( php -aam Terminal). Der Kommentar in jeder Zeile zeigt das Ergebnis.

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"

Das ist also meine Interpretation:

1. Der Null-Koaleszenz-Operator - ??:

  • ??ist wie ein "Tor", das nur NULL durchlässt .
  • Also, es gibt immer erste Parameter , es sei denn , erste Parameter sein geschiehtNULL .
  • Dies bedeutet ??dasselbe wie( !isset() || is_null() )

2. Der ternäre Operator - ?:

  • ?:ist wie ein Tor, das durchlässt anything falsy- einschließlichNULL
  • 0, empty string, NULL, false, !isset(), empty().. alles , was riecht falsy
  • Genau wie der klassische ternäre Operator: echo ($x ? $x : false)
  • HINWEIS: ?:Wirft PHP NOTICEundefinierte ( unsetoder !isset()) Variablen auf

3. Also Doktor, wann benutze ich ??und ?:..

  • Ich mache nur Spaß - ich bin kein Arzt und das ist nur eine Interpretation
  • Ich würde ?:wann verwenden
    • tun empty($x)Kontrollen
    • Klassische ternäre Operation wie !empty($x) ? $x : $ykann auf verkürzt werden$x ?: $y
    • if(!$x) { fn($x); } else { fn($y); } kann auf verkürzt werden fn(($x ?: $y))
  • Ich würde ??wann verwenden
    • Ich möchte einen !isset() || is_null()Scheck machen
    • zB prüfen ob ein Objekt existiert - $object = $object ?? new objClassName();

4. Stapeloperatoren ...

  1. Ternärer Operator kann gestapelt werden ...

    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

    Quelle & Gutschrift für diesen Code

    Dies ist im Grunde eine Folge von:

    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
  2. Null Coalese Operator kann gestapelt werden ...

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

    Dies ist eine Folge von:

    if(!isset($x) || is_null($x) ) {} 
    else if(!isset($y) || is_null($y) ) {}
    else {}
  3. Mit Stacking kann ich Folgendes verkürzen:

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

    Dazu:

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

    Cool, oder? :-)

a20
quelle
3
Mit Abstand die beste Antwort
Faizan Anwer Ali Rupani
69

Wenn Sie den ternären Verknüpfungsoperator wie folgt verwenden, wird ein Hinweis ausgegeben, wenn er $_GET['username']nicht festgelegt ist:

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

Also müssen Sie stattdessen so etwas tun:

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

Der Null-Koaleszenz-Operator entspricht der obigen Anweisung und gibt 'default' zurück, wenn er $_GET['username']nicht gesetzt ist oder ist null:

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

Beachten Sie, dass die Wahrhaftigkeit nicht überprüft wird . Es wird nur geprüft, ob es gesetzt und nicht null ist.

Sie können dies auch tun, und der erste definierte (festgelegte und nicht festgelegte null) Wert wird zurückgegeben:

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

Das ist ein richtiger Koaleszenzoperator.

Andrew
quelle
42

Der Hauptunterschied ist das

  1. Ternary Operator Ausdruck expr1 ?: expr3kehrt , expr1wenn expr1auswertet , um TRUEaber auf der anderen Seite Null Coalescing Operator Ausdruck (expr1) ?? (expr2) auswertet auf , expr1wenn expr1ist nicht NULL

  2. Der ternäre Operator gibt expr1 ?: expr3 eine Benachrichtigung aus, wenn der Wert auf der linken Seite (expr1) nicht vorhanden ist, andererseits jedoch der Null-Koaleszenz-Operator. Gibt (expr1) ?? (expr2) insbesondere keine Benachrichtigung aus, wenn der Wert auf der linken Seite (expr1) nicht vorhanden ist isset().

  3. TernaryOperator bleibt assoziativ

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

    Null Coalescing Operator ist richtig assoziativ

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

Lassen Sie uns nun den Unterschied anhand eines Beispiels erklären:

Ternärer Operator (?:)

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

Null-Koaleszenz-Operator (??)

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

Hier ist die Tabelle, die den Unterschied und die Ähnlichkeit zwischen '??'und erklärt?:

Geben Sie hier die Bildbeschreibung ein

Besonderer Hinweis: Der Null-Koaleszenz-Operator und der ternäre Operator sind ein Ausdruck, der nicht als Variable, sondern als Ergebnis eines Ausdrucks ausgewertet wird. Dies ist wichtig zu wissen, ob Sie eine Variable als Referenz zurückgeben möchten. Die Anweisung gibt $ foo zurück? $ bar; und $ var == 42 zurückgeben? $ a: $ b; In einer Return-by-Reference-Funktion funktioniert dies daher nicht und es wird eine Warnung ausgegeben.

Dhairya Lakhera
quelle
15

Beide verhalten sich beim dynamischen Datenhandling unterschiedlich.

Wenn die Variable leer ist (''), behandelt die Null-Koaleszenz die Variable als wahr, der ternäre Kurzoperator jedoch nicht. Und das ist etwas zu beachten.

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

Und die Ausgabe:

1b
2b

2d
1f

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

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

Chazy Chaz
quelle
Dies ist für PHP eindeutig kontraintuitiv, da eine leere Zeichenfolge normalerweise als falsch angesehen wird. Dennoch ist es in den Dokumenten für ??: deutlich angegeben It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
Simon
12

Beide sind Abkürzungen für längere Ausdrücke.

?:ist die Abkürzung für $a ? $a : $b. Dieser Ausdruck wird zu $ ​​a ausgewertet, wenn $ a zu TRUE ausgewertet wird .

??ist die Abkürzung für isset($a) ? $a : $b. Dieser Ausdruck wird zu $ ​​a ausgewertet, wenn $ a gesetzt und nicht null ist.

Ihre Anwendungsfälle überschneiden sich, wenn $ a undefiniert oder null ist. Wenn $ a undefiniert ist, ??wird kein E_NOTICE erzeugt, aber die Ergebnisse sind dieselben. Wenn $ a null ist, ist das Ergebnis dasselbe.

Dean Or. En
quelle
5

Für die Anfänger:

Null-Koaleszenz-Operator (??)

Alles ist wahr, außer nullWerte und undefiniert (Variablen- / Array-Index- / Objektattribute).

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"

Dies ist im Grunde genommen eine Überprüfung, ob die Variable (Array-Index, Objektattribut usw.) vorhanden ist und nicht null. ähnlich der issetFunktion

Kurzform des ternären Operators (? :)

alle falschen Dinge ( false, null, 0, leere Zeichenkette) als falsch kommen, aber wenn es eine ist nicht definiert es kommt auch als falsch , sondern Noticewerden werfen

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

Hoffe das hilft

Supun Praneeth
quelle
4

Scrollen Sie auf diesem Link nach unten und sehen Sie sich den Abschnitt an. Dort sehen Sie ein Vergleichsbeispiel wie folgt:

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

Es wird jedoch nicht empfohlen, die Operatoren zu verketten, da dies das Verständnis des Codes beim späteren Lesen erschwert.

Der Null-Koaleszenz-Operator (??) wurde als syntaktischer Zucker für den allgemeinen Fall hinzugefügt, dass in Verbindung mit isset () ein Ternär verwendet werden muss. Es gibt seinen ersten Operanden zurück, wenn er existiert und nicht NULL ist. Andernfalls wird der zweite Operand zurückgegeben.

Wenn Sie den Koaleszenzoperator verwenden, wird er im Gegensatz zum ternären Operator automatisch auf Null überprüft.

Script47
quelle
1
Bitte denken Sie nicht an Verkettung ... es ist so schwer zu lesen / zu verstehen wie verkettete Ternäre
Mark Baker
7
@MarkBaker Verkettete Ternäre sind schwer zu verstehen, da PHP die ternäre Assoziativität gebrochen hat. Dies gilt nicht für den Koaleszenzoperator, und eine verkettete Koaleszenz ist vollkommen verständlich.
NikiC
7
Ich stimme dir nicht zu. Das Verketten der Null-Koaleszenz ist eine großartige Funktion, und es macht es nicht schwer zu lesen, wenn Sie den Operator verstehen. Es wird häufig in Javascript verwendet und sobald sich die Leute in PHP damit vertraut gemacht haben, sollte dieser Aufruf, keine Verkettung zu verwenden, aufhören. Verkettung von Ternären ist sehr schwer zu lesen, aber Null-Koaleszenz ist einfach. Während Sie von links nach rechts lesen, wird nur aufgelistet, welcher Wert als nächstes verwendet werden soll.
Earl3s
2
Dies sieht dem allgemeinen a || b || cMuster in JS sehr ähnlich , außer dass PHPs für Boolesche Werte verwendet werden können ( false || 2in JS ist 2; false ?? 2in PHP ist falsch)
fregante
1
Ich bin nicht einverstanden mit Ihnen und anderen, wenn es darum geht, keine Verkettung zu verwenden. Es ist so, als würde man sagen, dass man niemals für Schleifen verwendet, weil man sie möglicherweise nicht versteht. Entwicklern / Codierern steht es frei, Codierungsstandards und -praktiken zu verwenden, die sie verstehen, auch wenn andere dies nicht tun. Persönlich sehe ich verkettetes Zusammenwachsen als sehr ähnlich zu switch-Anweisungen. Es gibt den ersten gefundenen Wert (set) und den letzten Wert zurück, wenn nichts gefunden wird.
kurdtpage
3

Die anderen Antworten gehen tief und geben großartige Erklärungen. Für diejenigen, die nach einer schnellen Antwort suchen,

$a ?: 'fallback' ist $a ? $a : 'fallback'

während

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


Der Hauptunterschied wäre, wenn der linke Operator entweder:

  • Ein falsy Wert, der nicht Null ist ( 0, '', false, [], ...)
  • Eine undefinierte Variable
Yaron U.
quelle
Es sollte keine $a =in der obigen Erweiterung von geben ??. $a ?? 'fallback' setzt oder ändert den Wert von $ a nicht. (Es wird lediglich ein Wert zurückgegeben).
Doin
2

Es scheint, dass es Vor- und Nachteile gibt, entweder ??oder zu verwenden ?:. Der Vorteil bei der Verwendung ?:ist, dass es false und null und "" gleich auswertet. Der Nachteil ist, dass ein E_NOTICE gemeldet wird, wenn das vorhergehende Argument null ist. Mit ??dem Pro ist, dass es kein E_NOTICE gibt, aber der Nachteil ist, dass es nicht falsch und null gleich bewertet. Nach meiner Erfahrung haben die Leute angefangen, null und false austauschbar zu verwenden, aber dann haben sie schließlich versucht, ihren Code so zu ändern, dass er entweder null oder false verwendet, aber nicht beide. Eine Alternative besteht darin, eine ausgefeiltere ternäre Bedingung zu schaffen : (isset($something) or !$something) ? $something : $something_else.

Das Folgende ist ein Beispiel für den Unterschied bei der Verwendung des ??Operators mit null und false:

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

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

Indem wir jedoch auf den ternären Operator eingehen, können wir dafür sorgen, dass sich eine falsche oder leere Zeichenfolge "" so verhält, als wäre sie eine Null, ohne eine e_notice auszulösen:

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

Persönlich denke ich, dass es wirklich schön wäre, wenn eine zukünftige Version von PHP einen weiteren neuen Operator enthalten würde: :?der die obige Syntax ersetzt. dh: // $var = $false :? "true";Diese Syntax würde null, false und "" gleichermaßen auswerten und kein E_NOTICE auslösen ...

Damian Green
quelle
3
Sie können $ var = $ false verwenden? null ?: "String ist leer / false / null / undefined";
RedSparr0w
Whoa ... die ?? null ?:Sache ist ziemlich genial, danke mr. schlauer Typ.
Blaine Lafreniere
1
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.
Čamo
quelle
0

Null Coalescing operatorführt nur zwei Aufgaben aus: es prüft whether the variable is setund whether it is null. Schauen Sie sich das folgende Beispiel an:

<?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'

Das obige Codebeispiel besagt, dass Null Coalescing operatoreine nicht vorhandene Variable und eine Variable, auf die gesetzt ist, auf NULLdieselbe Weise behandelt werden.

Null Coalescing operatorist eine Verbesserung gegenüber dem ternary operator. Schauen Sie sich das folgende Code-Snippet an, in dem die beiden verglichen werden:

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

Der Unterschied zwischen beiden besteht also darin, dass der Null Coalescing operatorOperator dafür ausgelegt ist, undefinierte Variablen besser zu verarbeiten als der ternary operator. Während das ternary operatoreine Abkürzung für ist if-else.

Null Coalescing operatorist nicht als Ersatz gedacht ternary operator, aber in einigen Anwendungsfällen wie im obigen Beispiel können Sie sauberen Code mit weniger Aufwand schreiben.

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

Pranav Rana
quelle
isset($_POST['fullname'])prüft bereits auf NULLWerte - daher ist das && !is_null($_POST['fullname'])im ersten Beispiel sowieso überflüssig
Yaron U.
0

Wenn Sie Superglobale wie $ _GET oder $ _REQUEST verwenden, sollten Sie sich bewusst sein, dass es sich um eine leere Zeichenfolge handeln kann. In diesem speziellen Fall dieses Beispiel

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

schlägt fehl, da der Wert von $ username jetzt eine leere Zeichenfolge ist.

Wenn Sie also $ _GET oder sogar $ _REQUEST verwenden, sollten Sie stattdessen den ternären Operator wie folgt verwenden:

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

Jetzt ist der Wert von $ username wie erwartet 'niemand'.

Alexander Behling
quelle
Guter Fang. Außerdem schlägt der Koaleszenzoperator auch bei einer leeren Zeichenfolge fehl.
Choxx