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
łysienie
źródło

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

MasterOdin
źródło
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? :-)

a20
źródło
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.

Andrzej
źródło
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.

Dhairya Lakhera
źródło
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

Chazy Chaz
źródło
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.

Dean Or
źródło
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

Supun Praneeth
źródło
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.

Skrypt47
źródło
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
Yaron U.
źródło
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 ...

Damian Green
źródło
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.
Čamo
źródło
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

Pranav Rana
źródło
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.

Alexander Behling
źródło
Dobry chwyt Ponadto operator koalescencyjny również zawiedzie w przypadku pustego łańcucha.
Choxx