Перевірте, чи значення є нульовим або нульовим


88

Мені потрібно перевірити, чи визначено значення як щось, включаючи null. issetобробляє нульові значення як невизначені та повертає false. Візьмемо для прикладу наступне:

$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

Зверніть увагу, що $barце невизначено.

Мені потрібно знайти умову, яка задовольняє наступним:

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

Будь-які ідеї?


19
if (isset ($ foo)) // повертає false, я впав зі стільця, всі ці роки ...
max4ever

in_array ($ key, array_keys ($ _ SESSION)) && is_null ($ _ SESSION [$ key]) Мені це цікаво було так довго ..
Джек

1
Для мене це не є нормальною поведінкою, isset= встановлено?, Ваша змінна має значення null. Я витратив багато часу через цей ...
Вінсент Деко,

Відповіді:


84

IIRC, ви можете використовувати get_defined_vars()для цього:

$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

+1 Я збирався запропонувати ту саму функцію, get_defined_varsщасливо справляється з сферою застосування.
салата

1
Здається, це працює, але я сподівався на щось простіше. Ну добре. Давайте подивимось, чи хтось може придумати один лайнер.
Тату Ульманен

4
ну, вам не потрібні vars, тому теоретично це один рядок "if (array_key_exists ('foo', get_defined_vars ())) {}"
Ганнес,

новий відповідь FVN в може бути швидшим способом , щоб отримати змінну , яка існує в поточному контексті, щоб уникнути витрат на get_defined_vars(): array_key_exists('foo', compact('foo')). Або швидше, якщо тестування глобальної: array_key_exists('foo', $GLOBALS).
ToolmakerSteve

25

Якщо ви маєте справу з властивостями об'єкта, які можуть мати значення NULL, ви можете використовувати: property_exists()замістьisset()

<?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();

?>

На відміну від isset (), property_exists () повертає TRUE, навіть якщо властивість має значення NULL.


11
Ви можете зробити те ж саме для масивів з array_key_exists ();
Calum

14

Див. Найкращий спосіб перевірити наявність змінної в PHP; isset () явно порушено

 if( array_key_exists('foo', $GLOBALS) && is_null($foo)) // true & true => true
 if( array_key_exists('bar', $GLOBALS) && is_null($bar)) // false &  => false

3
Код, який ви цитуєте, працює лише в тому випадку, якщо змінна знаходиться в глобальній області дії.
Raveline

Дійсно, але хіба це не найчастіший випадок? У функції у вас будуть змінні в глобальному масштабі та аргументи (які завжди визначаються). Ви також можете мати властивості об'єкта, але тоді ви можете використовувати 'property_exists'.
Loïc Février

Використання $ GLOBALS здається дещо мінливим, я повинен провести тестування сам, перш ніж я можу визнати це робочим.
Тату Ульманен,

4

Я виявив, що compactце функція, яка ігнорує невстановлені змінні, але діє з тими, для яких встановлено значення null, тому, коли у вас є велика локальна таблиця символів, я думаю, ви можете отримати більш ефективне рішення при перевірці array_key_exists('foo', get_defined_vars())за допомогою 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

Оновлення

З PHP 7.3 compact () буде повідомляти про невстановлені значення, тому, на жаль, ця альтернатива більше не діє.

compact () тепер видає помилку рівня E_NOTICE, якщо заданий рядок посилається на невстановлену змінну. Раніше такі рядки мовчки пропускались.


Цікава альтернатива. Але зауважте, що це, мабуть, повільніше, ніж виклик array_key_exists для існуючого масиву, наприклад $ GLOBALS, - оскільки пошук у хеш-таблиці не стає повільнішим, коли таблиця стає великою, і ви додали додаткову роботу compact. Тим не менше, я підтримав його, оскільки це корисно в одній ситуації: якщо ви хочете знати, чи fooіснує воно в поточному контексті , незалежно від того, звідки воно взялося - якщо вам все одно, місцеве чи глобальне, просто хочете знати, чи є воно існує.
ToolmakerSteve

@ToolmakerSteve - я насправді мав на увазі потенційно значні накладні витрати на дзвінки get_defined_vars. Дивіться тут .
nzn

1

Наступний код, написаний як розширення PHP, еквівалентний array_key_exists ($ name, get_defined_vars ()) (завдяки Henrik та 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;
    }

}

0

Ви можете використовувати is_null та empty замість isset (). Порожній не друкує повідомлення про помилку, якщо змінна не існує.


Я використовую is_null. Результат однаковий незалежно від isset.
Тату Улманен

Я помилився, розмістивши свою першу відповідь: чи пробували ви з empty ()?
Raveline

1
Це не буде працювати для значень, які не є порожніми і не мають значення NULL, наприклад FALSE, 0, array () або "".
Calum

1
Ця відповідь неправильна. is_nullмає таку ж проблему, як is_set: він не може розрізнити "не встановлено" та "встановлено на нуль", що є проблемою, яку має OP. emptyще гірше, як зазначає Калум.
ToolmakerSteve

0

Ось якийсь безглуздий обхідний шлях із використанням 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


-3

is_null($bar)повертає true, оскільки воно взагалі не має значень. Крім того, ви можете використовувати:

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

щоб перевірити, чи $barвизначено, і поверне true, лише якщо:

$bar = null;
if(isset($bar) && is_null($bar)) // returns true

Ні, він сказав, що це if(isset($bar))дає помилку, коли $bar = null.
Loïc Février

2
Це не передасть жодних інших змінних, окрім null (наприклад, if $bar = "test").
Тату Улманен

3
Коли $ bar = null isset () поверне "false", а is_null () поверне true. Помилкове та істинне дає завжди помилкове.
Bartek Kosa

Ця відповідь абсолютно помилкова. Як сказав OP, isset($bar)повертає false, навіть після $bar = null;.
ToolmakerSteve
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.