Fungsi menyatu untuk PHP?

131

Banyak bahasa pemrograman memiliki fungsi menyatu (mengembalikan nilai non-NULL pertama, misalnya ). PHP, sayangnya pada tahun 2009, tidak.

Apa yang akan menjadi cara yang baik untuk mengimplementasikan satu di PHP sampai PHP sendiri mendapat fungsi penggabungan?

mikl
sumber
11
Terkait: operator penggabungan nol baru ??untuk PHP 7.
kojiro
Informasi lebih lanjut tentang operator penggabungan nol dapat ditemukan di sini - stackoverflow.com/questions/33666256/…
Peter
1
Sekadar Catatan, PHP7 Menerapkan fucntion ini
Grzegorz
@ Grzegorz: Operator bukan fungsi, atau di mana Anda menemukan fungsi itu baru di PHP 7;)
hakre
Secara fungsi saya tidak bermaksud fungsi;) Fitur. Saya tidak tepat. Terima kasih :)
Grzegorz

Jawaban:

194

Ada operator baru di php 5.3 yang melakukan ini: ?:

// A
echo 'A' ?: 'B';

// B
echo '' ?: 'B';

// B
echo false ?: 'B';

// B
echo null ?: 'B';

Sumber: http://www.php.net/ChangeLog-5.php#5.3.0

Kevin
sumber
25
Bagaimana dengan beberapa cara pintas ternary, akankah sesuatu seperti "echo $ a?: $ B?: $ C?: $ D;" kerja?
ChrisR
5
Tidak berfungsi seperti yang diharapkan untuk array. Misalnya ketika mencoba memeriksa apakah elemen array yang tidak didefinisikan adalah falsey akan menghasilkan kesalahan. $input['properties']['range_low'] ?: '?'
Keyo
5
Anda harus mendapatkan pemberitahuan Indeks Tidak Terdefinisi terlepas dari penggunaan operator gabungan.
Kevin
2
Argumen falsey ganda mengembalikan argumen terakhir, array() ?: null ?: falsemengembalikan false. Operatornya memang waras.
Brad Koch
6
Perlu diingat bahwa ini tidak hanya menerima non-null seperti penggabungan dalam bahasa lain, tetapi nilai apa pun, yang akan secara implisit dikonversi menjadi boolean. Jadi pastikan Anda memoles aturan casting type
DanMan
65

PHP 7 memperkenalkan operator penyatuan nyata :

echo $_GET['doesNotExist'] ?? 'fallback'; // prints 'fallback'

Jika nilai sebelum ??tidak ada atau nullnilai setelah ??diambil.

Peningkatan atas ?:operator yang disebutkan adalah, bahwa ??juga menangani variabel yang tidak ditentukan tanpa melempar E_NOTICE.

flori
sumber
Akhirnya tidak ada lagi isset () dan kosong () di semua tempat!
George Kagan
7
@ timeNomad yang masih Anda butuhkan kosong, hanya memeriksa null
Nabeel Khan
Satu-satunya cara untuk mendapatkan "falsy-coalesce" yang aman adalah dengan menggunakan keduanya:($_GET['doesNotExist'] ?? null) ?: 'fallback'
Nathan Baulch
Namun, kelebihan ?:lebih dari ??itu adalah bahwa ia menyatukan nilai-nilai kosong juga yang ??tidak melakukannya. Mirip dengan perilaku operator OR logis dalam JavaScript (yaitu $val || 'default'), saya akan menemukan ?:menjadi bentuk yang lebih praktis penggabungan jika dalam praktik kami, kami akhirnya menemukan diri kami menangani kosong dan nol dengan cara yang sama (yaitu $val ?: 'default'). Dan jika Anda ingin memaksakan masalah ini lebih lanjut dan menelan E_NOTICE, Anda dapat memperdebatkan ini bahkan:echo @$val ?: 'default';
Matt Borja
29

Hit pertama untuk "php coalesce" di google.

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
      return $arg;
    }
  }
  return NULL;
}

http://drupial.com/content/php-coalesce

Will Shaver
sumber
9
Menyimpan sedikit ram dan jangan menduplikasi args ke dalam array, lakukan saja foreach (func_get_args () sebagai $ arg) {}
TravisO
17
@ [Alfred, Ciaran] - Anda salah. foreach () mengevaluasi argumen pertama hanya sekali, untuk mendapatkan array, dan kemudian mengulanginya.
gahooa
6
Menempatkan func_get_args () di dalam foreach (di sini sebagai $ arg) tidak akan mengubah apa pun dari sudut pandang kinerja.
Savageman
7
@Savageman ... tepatnya ... jika Anda berpikir untuk memeras kinerja milidetik ini atau beberapa byte memori dari aplikasi Anda, Anda mungkin melihat hambatan kinerja / memori yang salah
ChrisR
4
Ironisnya, ini sekarang menjadi hit pertama untuk "php coalesce" di Google.
Will Shaver
18

Saya sangat suka operator :? Sayangnya, ini belum diterapkan pada lingkungan produksi saya. Jadi saya menggunakan yang setara ini:

function coalesce() {
  return array_shift(array_filter(func_get_args()));
}
Ethan Kent
sumber
1
ini adalah 'kebenaran' menyatu, menggunakan array_filter untuk menyingkirkan segala sesuatu yang bernilai false (termasuk null) dalam argumen yang diteruskan. Dugaan saya menggunakan shift, bukan elemen pertama dalam array entah bagaimana lebih kuat, tapi itu bagian saya tidak tahu. lihat: php.net/manual/en/…
Adam Tolley
3
Saya menyukainya tetapi harus setuju dengan @hakre - coalesceseharusnya mengembalikan argumen non-nol pertama yang dihadapinya, yang akan mencakup FALSE. Fungsi ini akan membuang FALSE, mungkin bukan apa yang ada dalam pikiran (setidaknya bukan apa yang saya inginkan dari suatu coalescefungsi).
Madbreak
1
Hanya variabel yang harus dilewatkan dengan referensi
Ben Sinclair
9

Perlu dicatat bahwa karena perlakuan PHP terhadap variabel yang tidak diinisialisasi dan indeks array, segala jenis fungsi gabungan adalah penggunaan terbatas. Saya ingin sekali dapat melakukan ini:

$id = coalesce($_GET['id'], $_SESSION['id'], null);

Tetapi ini akan, dalam banyak kasus, menyebabkan kesalahan PHP dengan E_NOTICE. Satu-satunya cara aman untuk menguji keberadaan suatu variabel sebelum menggunakannya adalah menggunakannya secara langsung di blank () atau isset (). Operator ternary yang disarankan oleh Kevin adalah opsi terbaik jika Anda tahu bahwa semua opsi dalam gabungan Anda diketahui diinisialisasi.

Andrew
sumber
Dalam hal ini, serikat array bekerja dengan sangat baik ( $getstuff = $_GET+$_SESSION+array('id'=>null);$id=$getstuff['id'];).
Brilliand
@Apakah maksudnya? Apakah Anda solusi yang disarankan dengan referensi?
Ben Sinclair
PHP 7 memperkenalkan operator ternary penerbit baru yang indah ??untuk menjadikan operasi yang sangat umum ini lebih ringkas.
botimer
6

Pastikan Anda mengidentifikasi dengan tepat bagaimana Anda ingin fungsi ini bekerja dengan tipe tertentu. PHP memiliki beragam jenis pemeriksaan fungsi atau sejenisnya, jadi pastikan Anda tahu cara kerjanya. Ini adalah contoh perbandingan is_null () dan kosong ()

$testData = array(
  'FALSE'   => FALSE
  ,'0'      => 0
  ,'"0"'    => "0"  
  ,'NULL'   => NULL
  ,'array()'=> array()
  ,'new stdClass()' => new stdClass()
  ,'$undef' => $undef
);

foreach ( $testData as $key => $var )
{
  echo "$key " . (( empty( $var ) ) ? 'is' : 'is not') . " empty<br>";
  echo "$key " . (( is_null( $var ) ) ? 'is' : 'is not')  . " null<br>";
  echo '<hr>';
}

Seperti yang Anda lihat, kosong () mengembalikan true untuk semua ini, tetapi is_null () hanya melakukannya untuk 2 dari mereka.

Peter Bailey
sumber
2

Saya memperluas jawaban yang diposting oleh Ethan Kent . Jawaban itu akan membuang argumen non-nol yang mengevaluasi menjadi false karena cara kerja array_filter , yang bukan apa coalescefungsi biasanya. Sebagai contoh:

echo 42 === coalesce(null, 0, 42) ? 'Oops' : 'Hooray';

Ups

Untuk mengatasi ini, argumen kedua dan definisi fungsi diperlukan. Fungsi yang dapat dipanggil bertanggung jawab untuk memberi tahu array_filterapakah akan menambahkan nilai array saat ini ke array hasil atau tidak:

// "callable"
function not_null($i){
    return !is_null($i);  // strictly non-null, 'isset' possibly not as much
}

function coalesce(){
    // pass callable to array_filter
    return array_shift(array_filter(func_get_args(), 'not_null'));
}

Akan lebih baik jika Anda bisa melewati issetatau 'isset'sebagai argumen ke-2 array_filter, tetapi tidak beruntung.

Pecah-pecah
sumber
0

Saya sedang menggunakan ini, tapi saya ingin tahu apakah itu tidak dapat ditingkatkan dengan beberapa fitur baru di PHP 5.

function coalesce() {
  $args = func_get_args();
  foreach ($args as $arg) {
    if (!empty($arg)) {
    return $arg;
    }
  }
  return $args[0];
}
mikl
sumber
0

PHP 5.3+, dengan penutupan:

function coalesce()
{
    return array_shift(array_filter(func_get_args(), function ($value) {
        return !is_null($value);
    }));
}

Demo: https://eval.in/187365

Paulo Freitas
sumber
Hanya variabel yang harus dilewatkan dengan referensi
Ben Sinclair
Yup, saya melanggar aturan ketat untuk demo, hanya untuk membuatnya sederhana. :)
Paulo Freitas