Periksa apakah nilai isset dan null

90

Saya perlu memeriksa apakah nilai didefinisikan sebagai apa pun, termasuk nol. issetmemperlakukan nilai null sebagai tidak terdefinisi dan mengembalikan false. Ambil contoh berikut ini:

$foo = null;

if(isset($foo)) // returns false
if(isset($bar)) // returns false
if(isset($foo) || is_null($foo)) // returns true
if(isset($bar) || is_null($bar)) // returns true, raises a notice

Perhatikan bahwa $bartidak ditentukan.

Saya perlu menemukan kondisi yang memenuhi berikut ini:

if(something($bar)) // returns false;
if(something($foo)) // returns true;

Ada ide?

Tatu Ulmanen
sumber
20
if (isset ($ foo)) // return false, saya jatuh dari kursi, bertahun-tahun ...
max4ever
in_array ($ key, array_keys ($ _ SESSION)) && is_null ($ _ SESSION [$ key]) Saya sudah lama bertanya-tanya tentang ini ..
Jack
1
Ini bukan perilaku normal bagi saya, isset= disetel?, Variabel Anda disetel ke nol. Saya membuang banyak waktu karena yang satu ini ...
Vincent Decaux

Jawaban:

85

IIRC, Anda dapat menggunakan get_defined_vars()untuk ini:

$foo = NULL;
$vars = get_defined_vars();
if (array_key_exists('bar', $vars)) {}; // Should evaluate to FALSE
if (array_key_exists('foo', $vars)) {}; // Should evaluate to TRUE
Henrik Opel
sumber
+1 Saya akan menyarankan fungsi yang sama, get_defined_varsdengan senang hati mengatasi ruang lingkup.
salathe
1
Tampaknya berhasil, tetapi saya mengharapkan sesuatu yang lebih sederhana. Baiklah. Mari kita lihat apakah ada yang bisa membuat satu liner.
Tatu Ulmanen
4
yah, Anda tidak perlu vars, jadi secara teori satu baris "if (array_key_exists ('foo', get_defined_vars ())) {}"
Hannes
Jawaban yang lebih baru fvn ini mungkin cara yang lebih cepat untuk mendapatkan variabel yang ada dalam konteks saat ini, menghindari biaya dari get_defined_vars(): array_key_exists('foo', compact('foo')). Atau lebih cepat, jika pengujian global: array_key_exists('foo', $GLOBALS).
ToolmakerSteve
25

Jika Anda berurusan dengan properti objek yang mungkin memiliki nilai NULL, Anda dapat menggunakan: property_exists()sebagai gantiisset()

<?php

class myClass {
    public $mine;
    private $xpto;
    static protected $test;

    function test() {
        var_dump(property_exists($this, 'xpto')); //true
    }
}

var_dump(property_exists('myClass', 'mine'));   //true
var_dump(property_exists(new myClass, 'mine')); //true
var_dump(property_exists('myClass', 'xpto'));   //true, as of PHP 5.3.0
var_dump(property_exists('myClass', 'bar'));    //false
var_dump(property_exists('myClass', 'test'));   //true, as of PHP 5.3.0
myClass::test();

?>

Berbeda dengan isset (), property_exists () mengembalikan TRUE meskipun properti tersebut memiliki nilai NULL.

John Magnolia
sumber
11
Anda bisa melakukan hal yang sama untuk array dengan array_key_exists ();
teaqu
14

Lihat Cara terbaik untuk menguji keberadaan variabel di PHP; isset () jelas rusak

 if( array_key_exists('foo', $GLOBALS) && is_null($foo)) // true & true => true
 if( array_key_exists('bar', $GLOBALS) && is_null($bar)) // false &  => false
Loïc Février
sumber
3
Kode yang Anda kutip hanya berfungsi jika variabel berada dalam cakupan global.
Raveline
Memang tapi bukankah ini kasus yang paling sering terjadi? Dalam sebuah fungsi, Anda akan memiliki variabel dalam lingkup global dan argumen (yang selalu ditentukan). Anda juga dapat memiliki properti objek, tetapi kemudian Anda dapat menggunakan 'property_exists'.
Loïc Février
Menggunakan $ GLOBALS tampaknya agak tidak stabil, saya harus melakukan beberapa pengujian sendiri sebelum saya dapat menyatakan ini berfungsi.
Tatu Ulmanen
4

Saya telah menemukan itu compactadalah fungsi yang mengabaikan variabel yang tidak disetel tetapi berfungsi pada variabel yang disetel null, jadi ketika Anda memiliki tabel simbol lokal yang besar, saya akan membayangkan Anda bisa mendapatkan solusi yang lebih efisien daripada memeriksa array_key_exists('foo', get_defined_vars())dengan menggunakan array_key_exists('foo', compact('foo')):

$foo = null;
echo isset($foo) ? 'true' : 'false'; // false
echo array_key_exists('foo', compact('foo')) ? 'true' : 'false'; // true
echo isset($bar) ? 'true' : 'false'; // false
echo array_key_exists('bar', compact('bar')) ? 'true' : 'false'; // false

Memperbarui

Mulai PHP 7.3, compact () akan memberikan pemberitahuan untuk nilai yang tidak disetel, jadi sayangnya alternatif ini tidak lagi valid.

compact () sekarang mengeluarkan kesalahan level E_NOTICE jika string tertentu merujuk ke variabel yang tidak disetel. Sebelumnya, string semacam itu telah dilewati secara diam-diam.

nzn
sumber
Alternatif yang menarik. Tetapi perhatikan bahwa ini mungkin lebih lambat daripada memanggil array_key_exists pada array yang sudah ada, seperti $ GLOBALS - karena pencarian dalam tabel hash tidak menjadi lebih lambat, ketika tabel menjadi besar, dan Anda telah menambahkan pekerjaan tambahan compact. Namun demikian, saya memberi suara positif karena berguna dalam satu situasi: jika Anda ingin tahu apakah fooada dalam konteks saat ini , terlepas dari mana asalnya - jika Anda tidak peduli apakah itu lokal atau global, hanya ingin tahu apakah itu ada.
ToolmakerSteve
@ ToolmakerSteve - Saya sebenarnya mengacu pada overhead panggilan yang berpotensi signifikan get_defined_vars. Lihat disini .
nzn
1

Kode berikut yang ditulis sebagai ekstensi PHP setara dengan array_key_exists ($ name, get_defined_vars ()) (terima kasih kepada Henrik dan Hannes).

// get_defined_vars()
// https://github.com/php/php-src/blob/master/Zend/zend_builtin_functions.c#L1777
// array_key_exists
// https://github.com/php/php-src/blob/master/ext/standard/array.c#L4393

PHP_FUNCTION(is_defined_var)
{

    char *name;
    int name_len;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
        return;
    }

    if (!EG(active_symbol_table)) {
        zend_rebuild_symbol_table(TSRMLS_C);
    }

    if (zend_symtable_exists(EG(active_symbol_table), name, name_len + 1)) {
        RETURN_TRUE;
    }

}
masakielastik
sumber
0

Anda bisa menggunakan is_null dan empty sebagai ganti isset (). Empty tidak mencetak pesan kesalahan jika variabel tidak ada.

Raveline
sumber
Saya menggunakan is_null. Hasilnya sama terlepas dari isset.
Tatu Ulmanen
Saya membuat kesalahan saat memposting jawaban pertama saya: apakah Anda mencoba dengan empty ()?
Raveline
1
Ini tidak akan bekerja untuk nilai yang tidak kosong dan bukan NULL seperti FALSE, 0, array () atau "".
teaqu
1
Jawaban ini salah. is_nullmemiliki masalah yang sama seperti is_set: ia tidak dapat membedakan antara "not set" dan "set to null", yang merupakan masalah yang dimiliki OP. emptybahkan lebih buruk, seperti yang ditunjukkan Calum.
ToolmakerSteve
0

Berikut beberapa solusi konyol menggunakan xdebug. ;-)

function is_declared($name) {
    ob_start();
    xdebug_debug_zval($name);
    $content = ob_get_clean();

    return !empty($content);
}

$foo = null;
var_dump(is_declared('foo')); // -> true

$bla = 'bla';
var_dump(is_declared('bla')); // -> true

var_dump(is_declared('bar')); // -> false
Philippe Gerber
sumber
1
Tidak terlihat sangat portabel .. :)
Tatu Ulmanen
-3

is_null($bar)mengembalikan nilai true, karena tidak memiliki nilai sama sekali. Alternatifnya, Anda dapat menggunakan:

if(isset($bar) && is_null($bar)) // returns false

untuk memeriksa apakah $barsudah ditentukan dan hanya akan mengembalikan nilai true jika:

$bar = null;
if(isset($bar) && is_null($bar)) // returns true
Ruel
sumber
Tidak, dia bilang itu if(isset($bar))memberikan false saat $bar = null.
Loïc Février
2
Ini tidak akan melewatkan variabel lain selain null (misalnya jika $bar = "test").
Tatu Ulmanen
3
Ketika $ bar = null isset () akan mengembalikan "false" dan is_null () akan mengembalikan true. Salah dan benar selalu salah.
Bartek Kosa
Jawaban ini sepenuhnya salah. Seperti yang dikatakan OP, isset($bar)mengembalikan false, bahkan setelahnya $bar = null;.
ToolmakerSteve