Trójskładnikowy operator PHP a zerowy operator koalescencyjny


342

Czy ktoś może wyjaśnić różnice między skróconym operatorem trójskładnikowym ( ?:) a operatorem koalescencji zerowej ( ??) w PHP?

Kiedy zachowują się inaczej i kiedy w ten sam sposób (jeśli tak się dzieje)?

$a ?: $b

VS.

$a ?? $b

Odpowiedzi:


345

Kiedy twój pierwszy argument ma wartość NULL, są one w zasadzie takie same, z wyjątkiem tego, że koalescencja NULL nie daje E_NOTICEwyniku, gdy masz niezdefiniowaną zmienną. Dokumenty dotyczące migracji do PHP 7.0 zawierają następujące informacje:

Operator zerowania koalescencji (??) został dodany jako cukier składniowy w typowym przypadku konieczności używania trójskładnika w połączeniu z isset (). Zwraca swój pierwszy operand, jeśli istnieje i nie ma wartości NULL; w przeciwnym razie zwraca drugi operand.

Oto przykładowy kod, który to pokazuje:

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

Linie, które mają uwagę, to te, w których używam skróconego operatora trójskładnikowego, w przeciwieństwie do zerowego operatora koalescencyjnego. Jednak nawet z tym powiadomieniem PHP udzieli tej samej odpowiedzi.

Wykonaj kod: https://3v4l.org/McavC

Oczywiście zawsze zakłada się, że jest to pierwszy argument null. Kiedy już nie będzie już zerowy, to kończysz się różnicami w tym, że ??operator zawsze zwraca pierwszy argument, podczas gdy ?:stenografia będzie tylko wtedy, gdy pierwszy argument byłby prawdziwy, i to zależy od tego, jak PHP wypisze rzeczy na boolean .

Więc:

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

byłoby wtedy $arówne falsei $brówne 'g'.


8
Wskazówka: jeśli używasz? zamiast?: ale potem musisz dostosować swój kod do wersji PHP starszych niż 7 (np. dla wtyczki), wtedy możesz chcieć zamienić ?? z isset ($ coś)? $ coś: $ coś_elaż wszędzie w kodzie. Możesz to łatwo zrobić za pomocą Notepad ++ lub nedit (i innych edytorów) za pomocą narzędzia znajdź / zamień, wybierając opcję wyrażenia regularnego i wstawiając w polu wyszukiwania: „\ s * (\ S +) \ s * \? \?” oraz w polu zastępowania: „isset ($ 1)? $ 1:” bez cudzysłowów (nedit używa \ 1 zamiast 1 $). Następnie wymień wszystko.
Damian Green

14
To właściwa odpowiedź, jednak sprawdzenie prawdziwości jest zasadniczą różnicą i należy ją bardziej podkreślić.
mancze

2
@MasterOdin Niezadowolony z twojej odpowiedzi. Oba nie są takie same. Mają inny wynik.
Ciekawy

1
Warto zauważyć, że możesz użyć? z łańcuchem. Na przykład: $b = []; var_dump($b['a']['b']['c'] ?? 'default');lub z obiektami$b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
Jack B,

Pamiętaj, że zachowanie również jest inne $a = [];. Zobacz: 3v4l.org/iCCa0
Soullivaneuh

75

Uruchomiłem poniżej w interaktywnym trybie php ( php -ana terminalu). Komentarz do każdej linii pokazuje wynik.

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"

Oto moja interpretacja:

1. zerowy operator koalescencyjny - ??:

  • ??jest jak „brama”, która przepuszcza tylko NULL .
  • Tak więc zawsze zwraca pierwszy parametr , chyba że zdarzy się pierwszy parametrNULL .
  • To znaczy ?? że( !isset() || is_null() )

2. Operator trójskładnikowy - ?:

  • ?: jest jak brama, która pozwala anything falsy przepuszcza - w tymNULL
  • 0, empty string, NULL,false , !isset(), empty().. wszystko, co pachnie falsy
  • Podobnie jak klasyczny operator trójskładnikowy: echo ($x ? $x : false)
  • UWAGA: ?:wrzuci PHP NOTICEna niezdefiniowany ( unsetlub!isset() ) zmienne

3. Więc doktorze, kiedy używam ??i?: ...

  • Tylko żartuję - nie jestem lekarzem, a to tylko interpretacja
  • Użyłbym ?:kiedy
    • robić empty($x)kontrole
    • Klasyczna trójskładnikowa operacja, jak !empty($x) ? $x : $ymożna skrócić$x ?: $y
    • if(!$x) { fn($x); } else { fn($y); } można skrócić do fn(($x ?: $y))
  • Użyłbym ??kiedy
    • Chcę zrobić !isset() || is_null()sprawdzenie
    • np. sprawdź, czy obiekt istnieje - $object = $object ?? new objClassName();

4. Operatorzy układający w stos ...

  1. Operator trójskładnikowy można ustawiać w stos ...

    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

    Źródło i informacje o tym kodzie

    Jest to w zasadzie sekwencja:

    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
  2. Operator zerowy może być ustawiany w stos ...

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

    Jest to sekwencja:

    if(!isset($x) || is_null($x) ) {} 
    else if(!isset($y) || is_null($y) ) {}
    else {}
  3. Stosując stosy, mogę skrócić to:

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

    Do tego:

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

    Fajnie, prawda? :-)


3
Zdecydowanie najlepsza odpowiedź
Faizan Anwer Ali Rupani

69

Jeśli użyjesz skrótu trójskładnikowego operatora w ten sposób, spowoduje to powiadomienie, jeśli $_GET['username']nie zostanie ustawione:

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

Zamiast tego musisz zrobić coś takiego:

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

Operator zerowy koalescencyjny jest równoznaczne z powyższym stwierdzeniem, i powróci „default”, jeśli $_GET['username']nie jest ustawiona lub jest null:

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

Zauważ, że nie sprawdza prawdziwości . Sprawdza tylko, czy jest ustawiony, a nie zerowy.

Możesz to również zrobić, a pierwsza zdefiniowana (ustawiona i nie null) wartość zostanie zwrócona:

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

Teraz jest to właściwy operator koalescencyjny.


42

Główną różnicą jest to

  1. Wyrażenie operatora trójskładnikowegoexpr1 ?: expr3 zwraca wartość, expr1jeśli jest expr1przetwarzane, TRUEale z drugiej strony wyrażenie operatora zerowego koalescencji(expr1) ?? (expr2) ocenia, expr1jeśli nieexpr1 jest NULL

  2. Operator trójskładnikowy wysyła expr1 ?: expr3 powiadomienie, jeśli wartość po lewej stronie (expr1) nie istnieje, ale z drugiej strony zerowy operator koalescencyjny (expr1) ?? (expr2) W szczególności nie wysyła powiadomienia, jeśli wartość po lewej stronie (expr1) nie istnieje, podobnie jak isset().

  3. TernaryOperator pozostaje asocjacyjny

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

    Operator zerowego koalescencji ma rację asocjacji

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

Teraz wyjaśnijmy różnicę między przykładami:

Operator trójskładnikowy (?:)

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

Zerowy operator koalescencyjny (??)

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

Oto tabela wyjaśniająca różnicę i podobieństwo między '??'i?:

wprowadź opis zdjęcia tutaj

Uwaga specjalna: operator koalescencji zerowej i operator trójskładnikowy jest wyrażeniem, które nie ocenia wartości zmiennej, lecz wynik wyrażenia. Jest to ważne, aby wiedzieć, czy chcesz zwrócić zmienną przez odwołanie. Instrukcja zwraca $ foo ?? bar $; i zwróci $ var == 42? $ a: $ b; dlatego funkcja powrotu przez odniesienie nie będzie działać i zostanie wyświetlone ostrzeżenie.


15

Oba zachowują się inaczej, jeśli chodzi o dynamiczne przetwarzanie danych.

Jeśli zmienna jest pusta (''), koalescencja zerowa potraktuje zmienną jako prawdziwą, ale skrócony operator potrójny nie. I o tym należy pamiętać.

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

A wynik:

1b
2b

2d
1f

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

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


Jest to wyraźnie sprzeczne z intuicją w PHP, w którym pusty ciąg znaków jest zwykle uważany za fałszywy. Jednak jest to wyraźnie wskazane w dokumentacji dla ??: It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
Simon

12

Oba są skrótami dla dłuższych wyrażeń.

?:jest skrótem od $a ? $a : $b. To wyrażenie ma wartość $ a, jeśli $ a ma wartość PRAWDA .

??jest skrótem od isset($a) ? $a : $b. To wyrażenie będzie miało wartość $ a, jeśli $ a jest ustawione, a nie null.

Ich przypadki użycia pokrywają się, gdy $ a jest niezdefiniowany lub ma wartość null. Gdy $ a jest niezdefiniowane ??, nie wygeneruje E_NOTICE, ale wyniki są takie same. Gdy $ a jest zerowe, wynik jest taki sam.


5

Dla początkujących:

Zerowy operator koalescencyjny (??)

Wszystko jest prawdą, z wyjątkiem null wartości i niezdefiniowanych (zmienna / indeks tablicy / atrybuty obiektu)

dawny:

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

jest to w zasadzie sprawdzenie, czy zmienna (indeks tablicy, atrybut obiektu .. itd.) istnieje i nie istnieje null. podobny doisset funkcji

Skrócony operator trójskładnikowy (? :)

co fałszywe rzeczy ( false, null, 0, pusty łańcuch) są przyjść jako fałszywe, ale jeśli jest to niezdefiniowane pochodzić również jako fałszywe, ale Noticerzuci

dawny

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

Mam nadzieję że to pomoże


4

Przewiń w dół ten link i wyświetl sekcję, daje to porównawczy przykład, jak pokazano poniżej:

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

Nie zaleca się jednak łączenia łańcuchów operatorów, ponieważ utrudnia to zrozumienie kodu podczas jego późniejszego czytania.

Operator zerowania koalescencji (??) został dodany jako cukier składniowy w typowym przypadku konieczności używania trójskładnika w połączeniu z isset (). Zwraca swój pierwszy operand, jeśli istnieje i nie ma wartości NULL; w przeciwnym razie zwraca drugi operand.

Zasadniczo użycie operatora koalescencyjnego sprawi, że będzie ono automatycznie sprawdzać wartość zerową w przeciwieństwie do operatora trójskładnikowego.


1
Proszę nie rozważać tworzenia łańcuchów ... jest to tak trudne do odczytania / zrozumienia, jak łańcuchy trójskładnikowe
Mark Baker

7
@ MarkBaker Łańcuchy trójskładnikowe są trudne do zrozumienia, ponieważ PHP złamał trójskładnikowe skojarzenie. Nie dotyczy to operatora koalescencji, a koalescencja łańcuchowa imho jest całkowicie zrozumiała.
NikiC

7
Nie zgadzam się. Łączenie łańcuchów zerowych jest świetną funkcją i nie utrudnia czytania, jeśli rozumiesz operatora. Jest powszechnie używany w javascript i kiedy ludzie poczują się z tym dobrze w PHP, to wezwanie do nie używania łańcucha powinno się zakończyć. Łańcuchy trójskładnikowe są bardzo trudne do odczytania, ale łączenie zerowe jest łatwe. Kiedy czytasz od lewej do prawej, po prostu wyświetla listę wartości, które należy zastosować w następnej kolejności.
Earlss

2
Wygląda to bardzo podobnie do wspólnego a || b || cwzorca w JS, z wyjątkiem tego, że PHP może być użyte do logów ( false || 2w JS jest 2; false ?? 2w PHP jest fałsz)
fregante

1
Nie zgadzam się z tobą i innymi w związku z niestosowaniem łańcucha. To tak, jakby powiedzieć, że nigdy nie używaj pętli, ponieważ mogą ich nie rozumieć. Programiści / koderzy mają pełną swobodę w stosowaniu standardów i praktyk kodowania, które rozumieją, nawet jeśli inni tego nie robią. Osobiście uważam, że łączenie łańcuchowe jest bardzo podobne do instrukcji switch. Zwraca pierwszą znalezioną (ustawioną) wartość i ostatnią wartość, jeśli nic nie zostanie znalezione.
kurdtpage

3

Pozostałe odpowiedzi sięgają głęboko i dają świetne wyjaśnienia. Dla tych, którzy szukają szybkiej odpowiedzi,

$a ?: 'fallback' jest $a ? $a : 'fallback'

podczas

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


Główną różnicą byłoby, gdy lewy operator to:

  • Falsy wartość, która nie jest null ( 0, '', false, [], ...)
  • Niezdefiniowana zmienna

W $a =powyższym rozszerzeniu nie powinno być ??. $a ?? 'fallback' nie ustawia ani nie zmienia wartości $ a. (Zwraca jedynie wartość).
Doin

2

Wygląda na to, że istnieją zalety i wady korzystania z jednego ??lub ?:. Zaletą użycia ?:jest to, że ocenia fałsz, zero i to samo. Con polega na tym, że zgłasza E_NOTICE, jeśli poprzedzający argument jest pusty. Z ??pro jest to, że nie ma E_NOTICE, ale wada polega na tym, że nie ocenia on fałszu i zeruje to samo. Z mojego doświadczenia wynika, że ​​ludzie zaczęli używać zamiennie wartości NULL i FAŁSZ, ale w końcu uciekali się do modyfikacji kodu, aby był zgodny z użyciem wartości NULL lub FAŁSZ, ale nie obu. Alternatywą jest stworzenie bardziej rozbudowanego trójkowego warunku:(isset($something) or !$something) ? $something : $something_else .

Poniżej znajduje się przykład różnicy używania ??operatora przy użyciu zarówno wartości null, jak i false:

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

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

Opracowując operator potrójny, możemy jednak zrobić fałszywy lub pusty ciąg „” zachowując się tak, jakby był zerowy bez rzucania 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---

Osobiście uważam, że byłoby naprawdę miło, gdyby w przyszłej wersji PHP pojawił się inny nowy operator: :?który zastąpiłby powyższą składnię. tj.: // $var = $false :? "true";Ta składnia ocenia równe null, false i „” w równym stopniu i nie wyrzuca E_NOTICE ...


3
możesz użyć $ var = $ false ?? null?: "String is empty / false / null / undefined";
RedSparr0w

Zaraz ... ?? null ?:sprawa jest niesamowita, dziękuję, panie. mądry facet.
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 operatorwykonuje tylko dwa zadania: sprawdza whether the variable is seti whether it is null. Spójrz na następujący przykład:

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

Powyższy przykład kodu stanowi, że Null Coalescing operatortraktuje nieistniejącą zmienną i zmienną ustawioną NULLw ten sam sposób.

Null Coalescing operatorjest poprawą w stosunku do ternary operator. Spójrz na następujący fragment kodu porównujący oba:

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

Różnica między nimi polega na tym Null Coalescing operator, że operator jest zaprojektowany tak, aby lepiej obsługiwać niezdefiniowane zmienne ternary operator. Tymczasem ternary operatorjest to skrótif-else .

Null Coalescing operator nie ma na celu zastąpienia ternary operator , ale w niektórych przypadkach użycia, takich jak w powyższym przykładzie, pozwala na pisanie czystego kodu bez większych problemów.

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


isset($_POST['fullname'])już sprawdza NULLwartości - więc && !is_null($_POST['fullname'])w pierwszym przykładzie i tak jest zbędny
Yaron U.

0

Korzystając z superglobali, takich jak $ _GET lub $ _REQUEST, należy pamiętać, że mogą to być puste ciągi znaków. W tym szczególnym przypadku ten przykład

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

zakończy się niepowodzeniem, ponieważ wartość $ username jest teraz pustym ciągiem.

Tak więc, używając $ _GET, a nawet $ _REQUEST, powinieneś użyć operatora trójskładnikowego w następujący sposób:

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

Teraz wartością $ username jest „nikt”, zgodnie z oczekiwaniami.


Dobry chwyt Ponadto operator koalescencyjny również zawiedzie w przypadku pustego łańcucha.
Choxx
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.