Operator ternary PHP vs operator penggabungan nol


341

Adakah yang bisa menjelaskan perbedaan antara singkatan operator ternary ( ?:) dan operator penggabungan nol ( ??) di PHP?

Kapan mereka berperilaku berbeda dan kapan dengan cara yang sama (jika itu terjadi)?

$a ?: $b

VS.

$a ?? $b

Jawaban:


344

Ketika argumen pertama Anda adalah nol, mereka pada dasarnya sama kecuali bahwa penggabungan nol tidak akan menghasilkan E_NOTICEketika Anda memiliki variabel yang tidak ditentukan. The PHP 7.0 docs migrasi telah mengatakan ini:

Operator penggabungan nol (??) telah ditambahkan sebagai gula sintaksis untuk kasus umum yang memerlukan penggunaan terner dalam hubungannya dengan isset (). Ini mengembalikan operan pertamanya jika ada dan bukan NULL; selain itu mengembalikan operan keduanya.

Berikut beberapa contoh kode untuk menunjukkan ini:

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

Garis-garis yang memiliki pemberitahuan adalah yang saya gunakan operator steno singkat sebagai lawan dari operator penggabungan nol. Namun, bahkan dengan pemberitahuan tersebut, PHP akan memberikan respons yang sama kembali.

Jalankan kode: https://3v4l.org/McavC

Tentu saja, ini selalu dengan asumsi argumen pertama null. Setelah itu tidak lagi nol, maka Anda berakhir dengan perbedaan dalam hal ??operator akan selalu mengembalikan argumen pertama sedangkan ?:steno hanya akan jika argumen pertama benar, dan itu bergantung pada bagaimana PHP akan mengetikkan melemparkan hal-hal ke boolean .

Begitu:

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

maka $aakan sama dengan falsedan $bsama dengan 'g'.


8
Kiat: apakah Anda sudah menggunakan ?? bukan? dengan isset ($ something)? $ something: $ something_else di mana-mana dalam kode Anda. Anda dapat dengan mudah melakukan ini dengan Notepad ++ atau nedit (dan editor lain juga) menggunakan alat temukan / ganti, memilih opsi ekspresi reguler dan menyisipkan di bidang temukan: "\ s * (\ S +) \ s * \? \?" dan di kolom ganti: "isset ($ 1)? $ 1:" tanpa tanda kutip (nedit menggunakan \ 1 alih-alih $ 1). Lalu ganti semua.
Damian Green

14
Ini adalah jawaban yang tepat namun pemeriksaan kebenaran adalah perbedaan utama dan harus lebih ditekankan.
mancze

2
@MasterOdin Tidak puas dengan jawaban Anda. Keduanya tidak sama. Memiliki hasil berbeda.
Penasaran

1
Perlu dicatat bahwa Anda dapat menggunakan ?? dengan rantai. Misalnya: $b = []; var_dump($b['a']['b']['c'] ?? 'default');atau dengan benda$b = new Foo; var_dump($b->a()->b()->c() ?? 'default');
Jack B

Perlu diketahui bahwa perilaku ini juga berbeda dengan $a = [];. Lihat: 3v4l.org/iCCa0
Soullivaneuh

75

Jalankan di bawah ini pada mode interaktif php ( php -apada terminal). Komentar pada setiap baris menunjukkan hasilnya.

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"

Jadi ini interpretasi saya:

1. Operator Penggabungan Null - ??:

  • ??seperti "gerbang" yang hanya memungkinkan NULL masuk .
  • Jadi, selalu mengembalikan parameter pertama , kecuali parameter pertama terjadiNULL .
  • Ini berarti ??sama dengan( !isset() || is_null() )

2. Operator Ternary - ?:

  • ?:seperti gerbang yang memungkinkan anything falsy- termasukNULL
  • 0, empty string, NULL, false, !isset(), empty().. sesuatu yang berbau falsy
  • Sama seperti operator ternary klasik: echo ($x ? $x : false)
  • CATATAN: ?:akan menampilkan variabel yang PHP NOTICEtidak terdefinisi ( unsetatau !isset())

3. Jadi dokter, kapan saya menggunakan ??dan ?:..

  • Saya hanya bercanda - Saya bukan dokter dan ini hanya sebuah interpretasi
  • Saya akan gunakan ?:kapan
    • melakukan empty($x)cek
    • Operasi ternary klasik seperti !empty($x) ? $x : $ydapat disingkat$x ?: $y
    • if(!$x) { fn($x); } else { fn($y); } dapat disingkat menjadi fn(($x ?: $y))
  • Saya akan gunakan ??kapan
    • Saya ingin melakukan !isset() || is_null()cek
    • mis. periksa apakah suatu objek ada - $object = $object ?? new objClassName();

4. Menumpuk operator ...

  1. Operator Ternary dapat ditumpuk ...

    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

    Sumber & kredit untuk kode ini

    Ini pada dasarnya adalah urutan:

    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
  2. Operator Null Coalese dapat ditumpuk ...

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

    Ini adalah urutan dari:

    if(!isset($x) || is_null($x) ) {} 
    else if(!isset($y) || is_null($y) ) {}
    else {}
  3. Dengan menggunakan susun, saya dapat mempersingkat ini:

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

    Untuk ini:

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

    Keren kan? :-)


3
Sejauh ini jawaban terbaik
Faizan Anwer Ali Rupani

69

Jika Anda menggunakan operator ternary cara pintas seperti ini, itu akan menyebabkan pemberitahuan jika $_GET['username']tidak disetel:

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

Jadi, alih-alih Anda harus melakukan sesuatu seperti ini:

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

The Operator nol penggabungan setara dengan pernyataan di atas, dan akan kembali 'default' jika $_GET['username']tidak diatur atau null:

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

Perhatikan bahwa itu tidak memeriksa kebenaran . Ia memeriksa hanya jika diatur dan bukan nol.

Anda juga dapat melakukan ini, dan nilai yang ditentukan (ditetapkan dan tidak null) akan dikembalikan:

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

Nah, itu adalah operator penggabungan yang tepat.


42

Perbedaan utama adalah itu

  1. Ternary operator ekspresi expr1 ?: expr3kembali expr1jika expr1mengevaluasi ke TRUEtapi di sisi lain Null penggabungan Operator ekspresi (expr1) ?? (expr2) mengevaluasi ke expr1jika expr1ini tidak NULL

  2. Operator Ternary expr1 ?: expr3 mengeluarkan pemberitahuan jika nilai sisi kiri (expr1) tidak ada tetapi di sisi lain Operator Penggabungan Null (expr1) ?? (expr2) Secara khusus, tidak memancarkan pemberitahuan jika nilai sisi kiri (expr1) tidak ada, sama seperti isset().

  3. TernaryOperator dibiarkan asosiatif

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

    Operator Penggabungan Null adalah asosiatif yang tepat

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

Sekarang mari kita jelaskan perbedaan antara dengan contoh:

Operator ternary (?:)

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

Operator Penggabungan Null (??)

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

Berikut adalah tabel yang menjelaskan perbedaan dan kesamaan antara '??'dan?:

masukkan deskripsi gambar di sini

Catatan Khusus: operator penggabungan nol dan operator ternary adalah ekspresi, dan itu tidak mengevaluasi ke variabel, tetapi untuk hasil ekspresi. Ini penting untuk diketahui jika Anda ingin mengembalikan variabel dengan referensi. Pernyataan mengembalikan $ foo ?? $ bar; dan mengembalikan $ var == 42? $ a: $ b; karena itu fungsi pengembalian-oleh-referensi tidak akan berfungsi dan peringatan dikeluarkan.


15

Keduanya berperilaku berbeda dalam hal penanganan data dinamis.

Jika variabel kosong ('') penggabungan nol akan memperlakukan variabel sebagai true tetapi operator ternary steno tidak akan. Dan itu sesuatu yang ada dalam pikiran.

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

Dan hasilnya:

1b
2b

2d
1f

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

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


Ini jelas kontra-intuitif untuk PHP, di mana string kosong biasanya dianggap salah. Namun itu jelas ditunjukkan dalam dokumen untuk ??: It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
Simon

12

Keduanya adalah singkatan untuk ekspresi yang lebih panjang.

?:kependekan dari $a ? $a : $b. Ekspresi ini akan mengevaluasi ke $ a jika $ a mengevaluasi ke TRUE .

??kependekan dari isset($a) ? $a : $b. Ekspresi ini akan mengevaluasi ke $ a jika $ a diatur dan bukan nol.

Kasus penggunaannya tumpang tindih ketika $ a tidak terdefinisi atau nol. Ketika $ a tidak terdefinisi ??tidak akan menghasilkan E_NOTICE, tetapi hasilnya sama. Ketika $ a adalah null hasilnya sama.


5

Untuk pemula:

Operator penggabungan nol (??)

Semuanya benar kecuali nullnilai dan tidak terdefinisi (variabel / array indeks / atribut objek)

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"

ini pada dasarnya memeriksa variabel (indeks array, atribut objek .. dll) ada dan tidak null. mirip dengan issetfungsi

Tulisan singkat operator ternary (? :)

setiap hal-hal yang salah ( false, null, 0, string kosong) yang datang sebagai palsu, tetapi jika itu sebuah terdefinisi juga datang sebagai palsu tapi Noticeakan melemparkan

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

Semoga ini membantu


4

Gulir ke bawah pada tautan ini dan lihat bagian, itu memberi Anda contoh komparatif seperti terlihat di bawah:

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

Namun, tidak disarankan untuk menghubungkan operator karena akan membuat lebih sulit untuk memahami kode ketika membacanya nanti.

Operator penggabungan nol (??) telah ditambahkan sebagai gula sintaksis untuk kasus umum yang memerlukan penggunaan terner dalam hubungannya dengan isset (). Ini mengembalikan operan pertamanya jika ada dan bukan NULL; selain itu mengembalikan operan keduanya.

Pada dasarnya, menggunakan operator penyatuan akan membuatnya otomatis memeriksa null tidak seperti operator ternary.


1
Tolong jangan mempertimbangkan chaining ... membaca / memahami ini sama sulitnya dengan ternaries yang dirantai
Mark Baker

7
@MarkBaker Ternaries yang dirantai sulit untuk dipahami karena PHP telah merusak asosiatif ternary. Ini tidak berlaku untuk operator penggabungan dan penggabungan rantai imho sangat bisa dimengerti.
NikiC

7
Saya tidak setuju. Chaining the null coalesce adalah fitur yang sangat bagus, dan itu tidak membuatnya sulit dibaca jika Anda memahami operatornya. Ini biasanya digunakan dalam javascript dan sekali orang merasa nyaman dengan itu dalam PHP panggilan ini untuk tidak menggunakan rantai harus berhenti. Chiering ternaries sangat sulit dibaca, tetapi null coalesce mudah. Ketika Anda membaca dari kiri ke kanan hanya daftar nilai mana yang harus digunakan selanjutnya.
earl3s

2
Ini sangat mirip dengan a || b || cpola umum dalam JS, kecuali PHP dapat digunakan untuk boolean ( false || 2dalam JS adalah 2; false ?? 2dalam PHP salah)
fregant

1
Saya tidak setuju dengan Anda dan orang lain mengenai tidak menggunakan rantai. Ini seperti mengatakan jangan pernah gunakan untuk loop karena mungkin tidak memahaminya. Pengembang / pembuat kode bebas menggunakan standar pengkodean dan praktik yang mereka pahami, bahkan jika yang lain tidak. Secara pribadi, saya melihat penggabungan rantai sangat mirip dengan pergantian pernyataan. Ini mengembalikan nilai pertama yang ditemukan (ditetapkan), dan nilai terakhir jika tidak ada yang ditemukan.
kurdtpage

3

Jawaban yang lain masuk lebih dalam dan memberikan penjelasan yang bagus. Bagi mereka yang mencari jawaban cepat,

$a ?: 'fallback' adalah $a ? $a : 'fallback'

sementara

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


Perbedaan utama adalah ketika operator kiri adalah:

  • Nilai falsy yang TIDAK nol ( 0, '', false, [], ...)
  • Variabel tidak terdefinisi

Seharusnya tidak ada $a =ekspansi di atas ??. $a ?? 'fallback' tidak menetapkan atau mengubah nilai $ a. (Ini hanya mengembalikan nilai).
Doin

2

Tampaknya ada pro dan kontra untuk menggunakan salah satu ??atau ?:. Pro untuk menggunakan ?:adalah bahwa ia mengevaluasi false dan null dan "" sama. Yang salah adalah bahwa ia melaporkan E_NOTICE jika argumen sebelumnya adalah nol. Dengan ??pro adalah bahwa tidak ada E_NOTICE, tetapi masalahnya adalah tidak mengevaluasi false dan null sama. Dalam pengalaman saya, saya telah melihat orang-orang mulai menggunakan null dan false secara bergantian tetapi kemudian mereka akhirnya memodifikasi kode mereka agar konsisten dengan menggunakan null atau false, tetapi tidak keduanya. Sebuah alternatif adalah untuk menciptakan kondisi terner yang lebih rumit: (isset($something) or !$something) ? $something : $something_else.

Berikut ini adalah contoh perbedaan penggunaan ??operator menggunakan null dan false:

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

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

Namun dengan menguraikan operator ternary, kita dapat membuat string "" kosong atau kosong seolah-olah itu adalah nol tanpa melempar 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---

Secara pribadi, saya pikir akan sangat baik jika rev PHP masa depan termasuk operator baru: :?yang menggantikan sintaks di atas. yaitu: // $var = $false :? "true";Sintaks itu akan mengevaluasi null, false, dan "" sama-sama dan tidak melempar E_NOTICE ...


3
Anda dapat menggunakan $ var = $ false ?? null?: "String kosong / false / null / undefined";
RedSparr0w

Wah ... ?? null ?:masalahnya cukup luar biasa, terima kasih tuan. pria pintar.
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 operatormelakukan hanya dua tugas: memeriksa whether the variable is setdan whether it is null. Lihat contoh berikut:

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

Contoh kode di atas menyatakan bahwa Null Coalescing operatormemperlakukan variabel yang tidak ada dan variabel yang diatur dengan NULLcara yang sama.

Null Coalescing operatormerupakan peningkatan dari ternary operator. Lihat potongan kode berikut yang membandingkan keduanya:

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

Jadi, perbedaan antara keduanya adalah bahwa Null Coalescing operatoroperator dirancang untuk menangani variabel yang tidak terdefinisi lebih baik daripada ternary operator. Padahal, itu ternary operatoradalah singkatan untuk if-else.

Null Coalescing operatortidak dimaksudkan untuk menggantikan ternary operator, tetapi dalam beberapa kasus penggunaan seperti pada contoh di atas, ini memungkinkan Anda untuk menulis kode bersih dengan lebih mudah.

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


isset($_POST['fullname'])sudah memeriksa NULLnilai - jadi && !is_null($_POST['fullname'])contoh pertama adalah redundan
Yaron U

0

Saat menggunakan superglobals seperti $ _GET atau $ _REQUEST, Anda harus menyadari bahwa itu bisa berupa string kosong. Dalam kasus khusus ini, contoh ini

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

akan gagal karena nilai $ username sekarang adalah string kosong.

Jadi ketika menggunakan $ _GET atau bahkan $ _REQUEST Anda harus menggunakan operator ternary sebagai gantinya:

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

Sekarang nilai $ username adalah 'tidak ada' seperti yang diharapkan.


Tangkapan yang bagus. Selain itu, operator penggabungan juga akan gagal jika string kosong.
Choxx
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.