Operatore ternario PHP vs operatore a coalescenza nulla


342

Qualcuno può spiegare le differenze tra stenografia dell'operatore ternario ( ?:) e operatore a coalescenza nulla ( ??) in PHP?

Quando si comportano diversamente e quando allo stesso modo (se ciò accade)?

$a ?: $b

VS.

$a ?? $b

Risposte:


345

Quando il tuo primo argomento è nullo, sono sostanzialmente gli stessi tranne per il fatto che la coalescenza nulla non produrrà un E_NOTICEquando hai una variabile indefinita. I documenti di migrazione di PHP 7.0 hanno questo da dire:

L'operatore null coalescing (??) è stato aggiunto come zucchero sintattico per il caso comune di necessità di utilizzare un ternario insieme a isset (). Restituisce il suo primo operando se esiste e non è NULL; altrimenti restituisce il suo secondo operando.

Ecco alcuni esempi di codice per dimostrarlo:

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

Le linee che hanno l'avviso sono quelle in cui sto usando l'operatore stenografico stenografico al contrario dell'operatore a coalescenza nulla. Tuttavia, anche con l'avviso, PHP restituirà la stessa risposta.

Eseguire il codice: https://3v4l.org/McavC

Naturalmente, questo presuppone sempre che il primo argomento sia null. Una volta che non è più nullo, si ottengono differenze in quanto l' ??operatore restituisce sempre il primo argomento mentre la ?:scorciatoia lo farebbe solo se il primo argomento fosse veritiero, e ciò si basa sul modo in cui PHP scriverebbe le cose su un valore booleano .

Così:

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

sarebbe quindi $auguale falsee $buguale a 'g'.


8
Suggerimento: se hai utilizzato ?? invece? con isset ($ qualcosa)? $ qualcosa: $ qualcosa_else ovunque nel tuo codice. Puoi farlo facilmente con Notepad ++ o nedit (e anche con altri editor) usando lo strumento Trova / Sostituisci, selezionando l'opzione di espressione regolare e inserendo nel campo Trova: "\ s * (\ S +) \ s * \? \?" e nel campo di sostituzione: "isset ($ 1)? $ 1:" senza virgolette (nedit usa \ 1 invece di $ 1). Quindi sostituire tutto.
Damian Green,

14
Questa è la risposta giusta, tuttavia il controllo di veridicità è la maggiore differenza e dovrebbe essere più enfatizzato.
mancze

2
@MasterOdin Non soddisfatto della tua risposta. Entrambi non sono uguali. Hanno risultati diversi.
Curioso il

1
Vale la pena notare che puoi usare ?? con incatenamento. Ad esempio: $b = []; var_dump($b['a']['b']['c'] ?? 'default');o con oggetti$b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
Jack B

Si noti che anche il comportamento è diverso $a = [];. Vedi: 3v4l.org/iCCa0
Soullivaneuh

75

Ho eseguito quanto segue in modalità interattiva php ( php -asul terminale). Il commento su ogni riga mostra il risultato.

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"

Quindi questa è la mia interpretazione:

1. The Null Coalescing Operator - ??:

  • ??è come un "gate" che lascia passare solo NULL .
  • Quindi, restituisce sempre il primo parametro , a meno che non accada il primo parametroNULL .
  • Questo significa che ??è lo stesso( !isset() || is_null() )

2. L'operatore ternario - ?:

  • ?:è come un cancello che anything falsyattraversa - compresoNULL
  • 0, empty string, NULL, false, !isset(), empty().. tutto ciò che odora falsy
  • Proprio come il classico operatore ternario: echo ($x ? $x : false)
  • NOTA: ?:genererà variabili PHP NOTICEnon definite ( unseto !isset())

3. Quindi dottore, quando uso ??e ?:...

  • Sto solo scherzando: non sono un dottore e questa è solo un'interpretazione
  • Vorrei usare ?:quando
    • fare empty($x)controlli
    • L'operazione ternaria classica come !empty($x) ? $x : $ypuò essere accorciata$x ?: $y
    • if(!$x) { fn($x); } else { fn($y); } può essere abbreviato in fn(($x ?: $y))
  • Vorrei usare ??quando
    • Voglio fare un !isset() || is_null()controllo
    • ad es. verificare se esiste un oggetto - $object = $object ?? new objClassName();

4. Operatori di impilamento ...

  1. L'operatore ternario può essere impilato ...

    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

    Fonte e credito per questo codice

    Questa è sostanzialmente una sequenza di:

    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
  2. L'operatore Null Coalese può essere impilato ...

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

    Questa è una sequenza di:

    if(!isset($x) || is_null($x) ) {} 
    else if(!isset($y) || is_null($y) ) {}
    else {}
  3. Usando lo stacking, posso accorciare questo:

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

    A questa:

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

    Bene, vero? :-)


3
Di gran lunga la migliore risposta
Faizan Anwer Ali Rupani,

69

Se si utilizza l'operatore ternario di scelta rapida in questo modo, verrà generato un avviso se $_GET['username']non è impostato:

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

Quindi invece devi fare qualcosa del genere:

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

L' operatore null coalescing è equivalente all'istruzione precedente e restituirà 'default' se $_GET['username']non è impostato o è null:

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

Si noti che non verifica la verità . Controlla solo se è impostato e non è null.

Puoi anche farlo e il primo valore definito (impostato e non null) verrà restituito:

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

Questo è un vero operatore di coalescenza.


43

La differenza principale è quella

  1. L' espressione dell'operatore ternarioexpr1 ?: expr3 ritorna expr1se viene expr1valutata TRUEma, al contrario, l' espressione dell'operatore di coalescenza nulla(expr1) ?? (expr2) valuta expr1se non loexpr1 è NULL

  2. L'operatore ternario expr1 ?: expr3 emette un avviso se il valore sul lato sinistro (expr1) non esiste ma d'altro canto Null Coalescing Operator (expr1) ?? (expr2) In particolare, non emette un avviso se il valore sul lato sinistro (expr1) non esiste, proprio come isset().

  3. TernaryOperator è associativo a sinistra

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

    Null Coalescing Operator è il giusto associativo

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

Ora spieghiamo la differenza tra l'esempio:

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

Operatore di coalescenza nulla (??)

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

Ecco la tabella che spiega la differenza e la somiglianza tra '??'e?:

inserisci qui la descrizione dell'immagine

Nota speciale: l'operatore di coalescenza nulla e l'operatore ternario sono un'espressione e non valutano una variabile, ma il risultato di un'espressione. È importante sapere se si desidera restituire una variabile per riferimento. La dichiarazione restituisce $ foo ?? $ Bar; e restituire $ var == 42? $ a: $ b; in una funzione di ritorno per riferimento pertanto non funzionerà e verrà emesso un avviso.


15

Entrambi si comportano diversamente quando si tratta di gestione dinamica dei dati.

Se la variabile è vuota ('') la coalescenza nulla tratterà la variabile come vera, ma l'operatore sternale stenario no. E questo è qualcosa da tenere a mente.

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

E l'output:

1b
2b

2d
1f

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

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


Questo è chiaramente contro intuitivo per PHP, dove una stringa vuota è generalmente considerata falsa. Eppure è chiaramente indicato nei documenti per ??: It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
Simon,

12

Entrambi sono scorciatoie per espressioni più lunghe.

?:è l'abbreviazione di $a ? $a : $b. Questa espressione verrà valutata in $ a se $ a verrà valutata come TRUE .

??è l'abbreviazione di isset($a) ? $a : $b. Questa espressione verrà valutata in $ a se $ a è impostato e non è null.

I loro casi d'uso si sovrappongono quando $ a è indefinito o nullo. Quando $ a è indefinito ??non produrrà un E_NOTICE, ma i risultati sono gli stessi. Quando $ a è null, il risultato è lo stesso.


5

Per i principianti:

Operatore a coalescenza nulla (??)

Tutto è vero tranne i nullvalori e non definito (variabile / indice array / attributi oggetto)

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"

questo è fondamentalmente verificare che la variabile (indice dell'array, attributo oggetto ecc.) sia esistente e non null. simile alla issetfunzione

Stenografia dell'operatore ternario (? :)

ogni cose false ( false, null, 0, stringa vuota) sono venuti come false, ma se si tratta di un indefinito ma vengono anche come falso, ma Noticegetteranno

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

Spero che questo ti aiuti


4

Scorri verso il basso su questo link e visualizza la sezione, ti dà un esempio comparativo come mostrato di seguito:

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

Tuttavia, non è consigliabile incatenare gli operatori in quanto rende più difficile la comprensione del codice durante la lettura successiva.

L'operatore null coalescing (??) è stato aggiunto come zucchero sintattico per il caso comune di necessità di utilizzare un ternario insieme a isset (). Restituisce il suo primo operando se esiste e non è NULL; altrimenti restituisce il suo secondo operando.

In sostanza, l'uso dell'operatore coalescente lo farà controllare automaticamente per null a differenza dell'operatore ternario.


1
Per favore non prendere in considerazione il concatenamento ... è difficile da leggere / capire come ternari incatenati
Mark Baker

7
@MarkBaker I ternari incatenati sono difficili da capire perché PHP ha rotto l'associatività ternaria. Ciò non si applica all'operatore di coesione e la coesione incatenata è perfettamente comprensibile.
NikiC,

7
Non sono d'accordo. Concatenare la coalizione nulla è un'ottima caratteristica e non rende difficile leggere se si capisce l'operatore. È comunemente usato in JavaScript e una volta che le persone si sentono a proprio agio in PHP questa chiamata per non usare il concatenamento dovrebbe fermarsi. Concatenare i ternari è molto difficile da leggere, ma la coalescenza nulla è facile. Mentre leggi da sinistra a destra, elenca solo quale valore dovrebbe essere usato in seguito.
Earl3s

2
Questo assomiglia molto al a || b || cmodello comune in JS, tranne per i PHP che possono essere usati per i booleani ( false || 2in JS è 2; false ?? 2in PHP è falso)
fregante

1
Non sono d'accordo con te e gli altri riguardo al non usare il concatenamento. È come dire non usare mai i loop perché potrebbero non capirli. Gli sviluppatori / programmatori sono perfettamente liberi di usare gli standard e le pratiche di codifica che comprendono, anche se altri no. Personalmente, considero la coalescenza incatenata molto simile alle dichiarazioni di scambio. Restituisce il primo valore trovato (impostato) e l'ultimo valore se non viene trovato nulla.
kurdtpage il

3

Le altre risposte vanno in profondità e danno grandi spiegazioni. Per coloro che cercano una risposta rapida,

$a ?: 'fallback' è $a ? $a : 'fallback'

mentre

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


La differenza principale sarebbe quando l'operatore di sinistra è:

  • Un valore falsy che non è nullo ( 0, '', false, [], ...)
  • Una variabile non definita

Non ci dovrebbero essere $a =nell'espansione sopra di ??. $a ?? 'fallback' non imposta o modifica il valore di $ a. (Restituisce semplicemente un valore).
Doin

2

Sembra che ci siano pro e contro nell'utilizzare ??o ?:. Il pro da usare ?:è che valuta false e null e "" lo stesso. Il contro è che riporta un E_NOTICE se l'argomento precedente è nullo. Con ??il pro è che non esiste E_NOTICE, ma il contro è che non valuta false e null lo stesso. Nella mia esperienza, ho visto persone iniziare a usare null e false in modo intercambiabile, ma alla fine ricorrono a modificare il loro codice per essere coerenti con l'uso di null o false, ma non entrambi. Un'alternativa è quella di creare una condizione ternario più elaborato: (isset($something) or !$something) ? $something : $something_else.

Di seguito è riportato un esempio della differenza di utilizzo ??dell'operatore utilizzando sia null che false:

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

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

Elaborando l'operatore ternario, tuttavia, possiamo far sì che una stringa "" falsa o vuota si comporti come se fosse un valore nullo senza generare un e_notice:

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

Personalmente, penso che sarebbe davvero bello se un futuro rev di PHP includesse un altro nuovo operatore: :?che ha sostituito la sintassi sopra. vale a dire: // $var = $false :? "true";quella sintassi valuterà null, false e "" allo stesso modo e non genererà un E_NOTICE ...


3
puoi usare $ var = $ false ?? null?: "La stringa è vuota / false / null / undefined";
RedSparr0w,

Whoa ... la ?? null ?:cosa è davvero fantastica, grazie signor. ragazzo intelligente.
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.

0

Null Coalescing operatoresegue solo due compiti: controlla whether the variable is sete whether it is null. Dai un'occhiata al seguente esempio:

<?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'esempio di codice sopra riportato afferma che Null Coalescing operatortratta una variabile inesistente e una variabile impostata allo NULLstesso modo.

Null Coalescing operatorè un miglioramento rispetto al ternary operator. Dai un'occhiata al seguente frammento di codice confrontando i due:

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

Quindi, la differenza tra i due è che l' Null Coalescing operatoroperatore è progettato per gestire variabili indefinite meglio di ternary operator. Considerando che, ternary operatorè una scorciatoia per if-else.

Null Coalescing operatornon è destinato a sostituire ternary operator, ma in alcuni casi d'uso come nell'esempio precedente, consente di scrivere codice pulito con meno problemi.

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


isset($_POST['fullname'])controlla già i NULLvalori - quindi il && !is_null($_POST['fullname'])primo esempio è comunque ridondante
Yaron U.

0

Quando usi i superglobal come $ _GET o $ _REQUEST dovresti essere consapevole che potrebbero essere una stringa vuota. In questo caso specale questo esempio

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

fallirà perché il valore di $ username ora è una stringa vuota.

Quindi quando usi $ _GET o anche $ _REQUEST dovresti usare l'operatore ternario invece in questo modo:

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

Ora il valore di $ username è "none" come previsto.


Buona pesca. Inoltre, l'operatore di coalescenza fallirà anche nel caso di una stringa vuota.
Choxx
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.