Лучший способ проверить существование переменной в PHP;isset() явно нарушен

StackOverflow https://stackoverflow.com/questions/418066

  •  03-07-2019
  •  | 
  •  

Вопрос

Из самого isset() Документы:

isset() will return FALSE if testing a variable that has been set to NULL.

В основном, isset() проверяет не то, установлена ли переменная вообще, а то, установлена ли она на что-либо, кроме NULL.

Учитывая это, каков наилучший способ на самом деле проверить существование переменной?Я попробовал что-то вроде:

if(isset($v) || @is_null($v))

(тот самый @ необходимо избегать предупреждения, когда $v не задано), но is_null() имеет аналогичную проблему с isset():он возвращается TRUE о неустановленных переменных!Также представляется, что:

@($v === NULL)

работает точно так же, как @is_null($v), так что это тоже исключено.

Как мы должны надежно проверить существование переменной в PHP?


Редактировать:в PHP явно существует разница между переменными, которые не заданы, и переменными, для которых задано значение NULL:

<?php
$a = array('b' => NULL);
var_dump($a);

PHP показывает , что $a['b'] существует и обладает NULL ценность.Если вы добавите:

var_dump(isset($a['b']));
var_dump(isset($a['c']));

вы можете видеть двусмысленность, о которой я говорю, в отношении isset() функция.Вот результаты всех трех из них var_dump()s:

array(1) {
  ["b"]=>
  NULL
}
bool(false)
bool(false)

Дальнейшее редактирование:две вещи.

Во-первых, пример использования.Массив, превращаемый в данные SQL-файла UPDATE оператор, где ключами массива являются столбцы таблицы, а значениями массива являются значения, которые должны быть применены к каждому столбцу.Любой из столбцов таблицы может содержать NULL значение, обозначаемое передачей NULL значение в массиве.Ты потребность способ провести различие между несуществующим ключом массива и значением массива, равным NULL;в этом разница между тем, чтобы не обновлять значение столбца, и обновлением значения столбца до NULL.

Второй, Ответ Зоредача, array_key_exists() работает корректно для моего приведенного выше варианта использования и для любых глобальных переменных:

<?php
$a = NULL;
var_dump(array_key_exists('a', $GLOBALS));
var_dump(array_key_exists('b', $GLOBALS));

результаты:

bool(true)
bool(false)

Поскольку это правильно обрабатывается практически везде, я вижу, что существует какая-либо двусмысленность между переменными, которые не существуют, и переменными, для которых установлено значение NULL, Я звоню array_key_exists() официальный и самый простой способ в PHP по-настоящему проверить существование переменной.

(Единственный другой случай, о котором я могу подумать, - это для свойств класса, для которых есть property_exists(), который, согласно его документы, работает аналогично array_key_exists() в том смысле, что он правильно проводит различие между тем, что он не установлен, и тем, что он установлен на NULL.)

Это было полезно?

Решение

Если переменная, которую вы проверяете, будет находиться в глобальной области видимости, вы могли бы сделать:

array_key_exists('v', $GLOBALS) 

Другие советы

Попытка дать обзор различных обсуждений и ответов на них:

Нет единого ответа на этот вопрос, который мог бы заменить все способы isset может быть использован. Некоторые варианты использования решаются другими функциями, в то время как другие не выдерживают критики или имеют сомнительную ценность за пределами code golf.Другие варианты использования далеки от того, чтобы быть "сломанными" или "непоследовательными", и демонстрируют, почему issetреакция на null это логичное поведение.

Реальные варианты использования (с решениями)

1.Массив ключей

Массивы можно рассматривать как наборы переменных, с unset и isset обращаться с ними так, как если бы они были.Однако, поскольку они могут быть повторены, подсчитаны и т.д., пропущенное значение не совпадает с тем, значение которого равно null.

Ответ в данном случае заключается в том, чтобы использование array_key_exists() вместо того , чтобы isset().

Поскольку this принимает массив для проверки в качестве аргумента функции, PHP все равно будет выдавать "уведомления", если сам массив не существует.В некоторых случаях можно обоснованно утверждать, что каждое измерение должно было быть инициализировано первым, поэтому уведомление выполняет свою работу.Для других случаев "рекурсивный" array_key_exists функция, которая проверяла каждое измерение массива по очереди, позволила бы избежать этого, но в основном была бы такой же, как @array_key_exists.Это также в некоторой степени связано с обработкой null ценности.

2.Свойства объекта

В традиционной теории "Объектно-ориентированного программирования" инкапсуляция и полиморфизм являются ключевыми свойствами объектов;в реализации ООП на основе классов, такой как PHP, инкапсулированные свойства объявляются как часть определения класса и задаются уровни доступа (public, protected, или private).

Однако PHP также позволяет вам динамически добавлять свойства к объекту, подобно ключам к массиву, и некоторые люди используют объекты без классов (технически, экземпляры встроенных stdClass, у которого нет методов или частной функциональности) аналогично ассоциативным массивам.Это приводит к ситуациям, когда функция может захотеть узнать, было ли добавлено определенное свойство к предоставленному ей объекту.

Как и в случае с ключами массива, решение для проверки свойств объекта включено в язык, называемый, достаточно разумно, property_exists.

Неоправданные варианты использования с обсуждением

3. register_globals, и другое загрязнение глобального пространства имен

Тот самый register_globals функция добавила переменные в глобальную область видимости, имена которых были определены аспектами HTTP-запроса (параметры GET и POST, а также файлы cookie).Это может привести к появлению глючного и небезопасного кода, именно поэтому с тех пор он был отключен по умолчанию PHP 4.2, выпущен в августе 2000 года и полностью удален в PHP 5.4, выпущен в марте 2012.Однако вполне возможно, что некоторые системы все еще работают с включенной или эмулируемой этой функцией.Также возможно "загрязнить" глобальное пространство имен другими способами, используя global ключевое слово, или $GLOBALS массив.

Во - первых, register_globals само по себе вряд ли неожиданно приведет к null переменная, поскольку значения GET, POST и cookie всегда будут строками (с '' все еще возвращаешься true От isset), а переменные в сеансе должны полностью находиться под контролем программиста.

Во-вторых, загрязнение переменной значением null это проблема только в том случае, если при этом перезаписывается некоторая предыдущая инициализация."Перезаписывание" неинициализированной переменной с null было бы проблематично только в том случае, если бы код где-то еще проводил различие между двумя состояниями, так что сама по себе эта возможность является аргументом против проводя такое различие.

4. get_defined_vars и compact

Несколько редко используемых функций в PHP, таких как get_defined_vars и compact, позволяют вам обрабатывать имена переменных так, как если бы они были ключами в массиве.Для глобальных переменных, сверхглобальный массив $GLOBALS допускает аналогичный доступ и является более распространенным.Эти методы доступа будут вести себя по-разному, если переменная не определена в соответствующей области видимости.

После того как вы решили обрабатывать набор переменных как массив, используя один из этих механизмов, вы можете выполнять с ним все те же операции, что и с любым обычным массивом.Следовательно, см. 1.

Функциональность, которая существовала только для того, чтобы предсказать, как эти функции будут вести себя (например"будет ли ключ "foo" в массиве, возвращаемом get_defined_vars?") является излишним, поскольку вы можете просто запустить функцию и выяснить это без каких-либо побочных эффектов.

4а.Переменные переменные ($$foo)

Хотя это не совсем то же самое, что функции, которые превращают набор переменных в ассоциативный массив, в большинстве случаев используются "переменные переменные" ("присвоить переменной с именем, основанным на этой другой переменной") можно и нужно изменить, чтобы вместо этого использовать ассоциативный массив.

Имя переменной, по сути, - это метка, присваиваемая значению программистом;если вы определяете его во время выполнения, то на самом деле это не метка, а ключ в каком-то хранилище ключ-значение.Более практично, не используя массив, вы теряете способность подсчитывать, выполнять итерации и т. Д;также может стать невозможным иметь переменную "вне" хранилища ключ-значение, поскольку она может быть перезаписана $$foo.

После изменения на использование ассоциативного массива код будет соответствовать решению 1.Косвенный доступ к свойству объекта (например, $foo->$property_name) можно решить с помощью решения 2.

5. isset печатать намного проще, чем array_key_exists

Я не уверен, что это действительно актуально, но да, имена функций PHP иногда могут быть довольно многословными и непоследовательными.По-видимому, доисторические версии PHP использовали длину имени функции в качестве хэш-ключа, поэтому Расмус намеренно придумал такие имена функций, как htmlspecialchars таким образом, у них было бы необычное количество символов...

И все же, по крайней мере, мы не пишем Java, а?;)

6.Неинициализированные переменные имеют тип

Тот самый страница руководства по основам переменных включает в себя это утверждение:

Неинициализированные переменные имеют значение по умолчанию своего типа в зависимости от контекста, в котором они используются

Я не уверен, есть ли в движке Zend какое-то понятие "неинициализированный, но известный тип" или это слишком много значит для оператора.

Ясно то, что это не имеет практического значения для их поведения, поскольку поведение, описанное на этой странице для неинициализированных переменных, идентично поведению переменной, значение которой равно null.Чтобы выбрать один пример, оба $a и $b в этом коде результат будет выглядеть как целое число 42:

unset($a);
$a += 42;

$b = null;
$b += 42;

(Первый вызовет уведомление о необъявленной переменной в попытке заставить вас написать лучший код, но это не будет иметь никакого значения для того, как код на самом деле выполняется.)

99.Определение того, была ли запущена функция

(Этот оставляю напоследок, так как он намного длиннее остальных.Может быть, я отредактирую это позже ...)

Рассмотрим следующий код:

$test_value = 'hello';
foreach ( $list_of_things as $thing ) {
    if ( some_test($thing, $test_value) ) {
        $result = some_function($thing);
    }
}
if ( isset($result) ) {
    echo 'The test passed at least once!';
}

Если some_function может вернуться null, существует вероятность того, что echo до вас не доберутся, даже если some_test возвращенный true.Намерение программиста состояло в том, чтобы определить, когда $result никогда не были установлены, но PHP не позволяет им этого делать.

Однако при таком подходе есть и другие проблемы, которые становятся понятными, если вы добавляете внешний цикл:

foreach ( $list_of_tests as $test_value ) {
    // something's missing here...
    foreach ( $list_of_things as $thing ) {
        if ( some_test($thing, $test_value) ) {
            $result = some_function($thing);
        }
    }
    if ( isset($result) ) {
        echo 'The test passed at least once!';
    }
}

Потому что $result никогда не инициализируется явно, оно примет значение при прохождении самого первого теста, что делает невозможным определить, прошли ли последующие тесты или нет. На самом деле это чрезвычайно распространенная ошибка, когда переменные не инициализируются должным образом.

Чтобы исправить это, нам нужно что-то сделать в строке, где я прокомментировал, что чего-то не хватает.Наиболее очевидным решением является установка $result к "конечной стоимости", которая some_function никогда не смогу вернуться;если это null, тогда остальная часть кода будет работать нормально.Если нет естественного кандидата на конечное значение, потому что some_function имеет крайне непредсказуемый возвращаемый тип (что, вероятно, само по себе является плохим знаком), затем дополнительное логическое значение, например $found, можно было бы использовать вместо этого.

Мысленный эксперимент номер один:тот самый very_null постоянный

PHP теоретически мог бы предоставить специальную константу, а также null - для использования в качестве конечного значения здесь;предположительно, было бы незаконно возвращать это из функции, или это было бы принудительно null, и то же самое, вероятно, было бы применимо к передаче его в качестве аргумента функции.Это сделало бы этот очень конкретный случай немного проще, но как только вы решили бы переработать код - например, поместить внутренний цикл в отдельную функцию, - это стало бы бесполезным.Если бы константа могла передаваться между функциями, вы не могли бы гарантировать, что some_function не вернул бы его, так что оно больше не было бы полезно в качестве универсального терминального значения.

Аргумент для обнаружения неинициализированных переменных в этом случае сводится к аргументу для этой специальной константы:если вы замените комментарий на unset($result), и относиться к этому иначе , чем $result = null, вы вводите "значение" для $result это не может быть передано другим пользователям и может быть обнаружено только с помощью определенных встроенных функций.

Мысленный эксперимент номер два:счетчик присвоений

Другой способ размышления о том, что было последним if спрашивает: "было ли что-нибудь назначено для $result?" Вместо того, чтобы рассматривать это как особую ценность $result, возможно, вы могли бы думать об этом как о "метаданных". о нас переменная, немного похожая на Perl's "variable tainting".Так что вместо того , чтобы isset вы могли бы назвать это has_been_assigned_to, и вместо того , чтобы unset, reset_assignment_state.

Но если это так, зачем останавливаться на логическом значении?Что, если ты захочешь знать сколько раз тест пройден;вы могли бы просто расширить свои метаданные до целого числа и иметь get_assignment_count и reset_assignment_count...

Очевидно, что добавление такой функции привело бы к снижению сложности и производительности языка, поэтому ее необходимо было бы тщательно взвесить с учетом ее ожидаемой полезности.Как и в случае с very_null постоянный, он был бы полезен только в очень узких обстоятельствах и был бы столь же устойчив к повторному факторингу.

Надеюсь, очевидный вопрос заключается в том, почему движок выполнения PHP должен заранее предполагать, что вы хотите отслеживать такие вещи, вместо того, чтобы предоставлять вам делать это явно, используя обычный код.

Иногда я немного теряюсь, пытаясь понять, какую операцию сравнения использовать в данной ситуации. isset() применяется только к неинициализированным или явно нулевым значениям.Передача / присвоение null - отличный способ гарантировать, что логическое сравнение работает должным образом.

Тем не менее, об этом немного сложно думать, поэтому вот простая матрица, сравнивающая, как разные значения будут оцениваться различными операциями:

|           | ===null | is_null | isset | empty | if/else | ternary | count>0 |
| -----     | -----   | -----   | ----- | ----- | -----   | -----   | -----   |
| $a;       | true    | true    |       | true  |         |         |         |
| null      | true    | true    |       | true  |         |         |         |
| []        |         |         | true  | true  |         |         |         |
| 0         |         |         | true  | true  |         |         | true    |
| ""        |         |         | true  | true  |         |         | true    |
| 1         |         |         | true  |       | true    | true    | true    |
| -1        |         |         | true  |       | true    | true    | true    |
| " "       |         |         | true  |       | true    | true    | true    |
| "str"     |         |         | true  |       | true    | true    | true    |
| [0,1]     |         |         | true  |       | true    | true    | true    |
| new Class |         |         | true  |       | true    | true    | true    |

Чтобы соответствовать таблице, я немного сжал метки:

  • $a; ссылается на объявленную, но неназначенную переменную
  • все остальное в первом столбце относится к присвоенному значению, например:
    • $a = null;
    • $a = [];
    • $a = 0;
  • столбцы относятся к операциям сравнения, таким как:
    • $a === null
    • isset($a)
    • empty($a)
    • $a ? true : false

Все результаты являются логическими, true печатается и false опущен.

Вы можете запустить тесты самостоятельно, проверьте эту суть:
https://gist.github.com/mfdj/8165967

Вы можете использовать конструкцию compact language для проверки существования переменной null.Переменные, которые не существуют, не появятся в результате, в то время как будут показаны нулевые значения.

$x = null;
$y = 'y';

$r = compact('x', 'y', 'z');
print_r($r);

// Output:
// Array ( 
//  [x] => 
//  [y] => y 
// ) 

В случае с вашим примером:

if (compact('v')) {
   // True if $v exists, even when null. 
   // False on var $v; without assignment and when $v does not exist.
}

Конечно, для переменных в глобальной области видимости вы также можете использовать array_key_exists() .

Б.Т.В.лично я бы избегал ситуаций, подобных чуме, когда существует семантическая разница между несуществующей переменной и переменной, имеющей нулевое значение.PHP и большинство других языков просто не думают, что их существует.

Объясняющий НОЛЬ, логически мыслящий

Я думаю, очевидный ответ на все это таков...Не инициализируйте свои переменные как NULL, инициализируйте их как нечто, имеющее отношение к тому, чем они должны стать.

Обрабатывайте NULL должным образом

Значение NULL следует рассматривать как "несуществующее значение", что и означает значение NULL.Переменная не может быть классифицирована как существующая в PHP, потому что ей не было указано, каким типом сущности она пытается быть.С таким же успехом его может и не существовать, поэтому PHP просто говорит "Хорошо, это не так, потому что в этом все равно нет смысла, и NULL - это мой способ сказать это".

Аргумент

Давайте поспорим сейчас."Но NULL - это все равно, что сказать 0, или FALSE, или ".

Неверно, 0-FALSE-" все по-прежнему классифицируются как пустые значения, но они указаны как некоторый тип значения или заранее определенный ответ на вопрос. ЛОЖЬ это ответ "да" или "нет",'' является ли ответом на заголовок, который кто-то отправил, и 0 это ответ на вопрос о количестве, времени и т.д.Они задаются как некоторый тип ответа / результата, который делает их действительными как установленные.

NULL - это просто отсутствие ответа, что бы там ни было, оно не говорит нам "да" или "нет", и оно не сообщает нам время, и оно не сообщает нам, что была отправлена пустая строка.Это основная логика в понимании NULL.

Краткие сведения

Речь идет не о создании дурацких функций, чтобы обойти проблему, это просто изменение взгляда вашего мозга на NULL.Если оно равно NULL, предположим, что оно не задано как что-либо еще.Если вы предварительно определяете переменные, то предварительно определите их как 0, FALSE или "" в зависимости от типа использования, которое вы собираетесь для них использовать.

Не стесняйтесь процитировать это.Это не укладывается у меня в голове :)

Свойства объекта могут быть проверены на наличие с помощью проперти_существует

Пример из модульного теста:

function testPropertiesExist()
{
    $sl =& $this->system_log;
    $props = array('log_id',
                   'type',
                   'message',
                   'username',
                   'ip_address',
                   'date_added');

    foreach($props as $prop) {
        $this->assertTrue(property_exists($sl, $prop),
                           "Property <{$prop}> exists");
    }
}

В качестве дополнения к обсуждение greatbigmassive того, что означает NULL, рассмотрим, что на самом деле означает "существование переменной".

Во многих языках вы должны явно объявлять каждую переменную, прежде чем использовать ее;это может определить его тип, но что более важно, он объявляет свой область применения.Переменная "существует" везде в своей области видимости и нигде за ее пределами - будь то целая функция или отдельный "блок".

В пределах своей области видимости переменная присваивает метке некоторое значение который вы, программист, выбрали.Вне своей области действия эта метка бессмысленна (используете ли вы ту же метку в другой области, в принципе, не имеет значения).

В PHP переменные объявлять не нужно - они оживают, как только они тебе понадобятся.Когда вы записываете в переменную в первый раз, PHP выделяет запись в памяти для этой переменной.Если вы читаете из переменной, в которой в данный момент нет записи, PHP считает, что эта переменная имеет значение NULL.

Однако автоматические детекторы качества кода обычно предупреждают вас, если вы используете переменную без ее предварительной "инициализации".Во-первых, это помогает обнаружить опечатки, такие как присвоение $thingId но чтение из $thing_id;но, во-вторых, это заставляет вас учитывать область, в которой эта переменная имеет значение, точно так же, как это было бы при объявлении.

Любой код, который заботится о том, "существует" ли переменная, является частью области видимости этой переменной - независимо от того, была ли она инициализирована или нет, вы как программист придали этой метке значение в этом месте кода.Поскольку вы используете его, он должен в каком-то смысле "существовать", и если он существует, то должен иметь неявное значение;в PHP это неявное значение равно null.

Из-за того, как работает PHP, можно написать код, который обрабатывает пространство имен существующих переменных не как область действия меток, которым вы придали значение, а как своего рода хранилище ключ-значение.Вы можете, например, запустить такой код, как этот: $var = $_GET['var_name']; $$var = $_GET['var_value'];. Просто потому, что вы можете, еще не значит, что это хорошая идея.

Оказывается, в PHP есть гораздо лучший способ представления хранилищ ключ-значение, называемых ассоциативными массивами.И хотя значения массива можно обрабатывать как переменные, вы также можете выполнять операции со всем массивом в целом. Если у вас есть ассоциативный массив, вы можете проверить, содержит ли он ключ, используя array_key_exists().

Вы также можете использовать объекты аналогичным образом, динамически задавая свойства, и в этом случае вы можете использовать property_exists() точно таким же образом.Конечно, если вы определяете класс, вы можете объявить, какими свойствами он обладает - вы даже можете выбирать между public, private, и protected сфера применения.

Хотя есть технический разница между переменной (в отличие от ключа массива или свойства объекта), которая не была инициализирована (или которая была явно unset()) и тот , чья ценность равна null, любой код , который считает это различие равным значимый использует переменные так, как они не предназначены для использования.

isset проверяет, установлена ли переменная и, если да, является ли ее значение не является НУЛЕВЫМ.Последняя часть (на мой взгляд) не входит в сферу действия этой функции.Не существует достойного обходного пути для определения того, является ли переменная нулевой потому что он не установлен или потому , что ему явно присвоено значение NULL.

Вот одно из возможных решений:

$e1 = error_get_last();
$isNULL = is_null(@$x);
$e2 = error_get_last();
$isNOTSET = $e1 != $e2;
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0

Другим обходным путем является проверка выходных данных get_defined_vars():

$vars = get_defined_vars();
$isNOTSET = !array_key_exists("x", $vars);
$isNULL = $isNOTSET ? true : is_null($x);
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0

Я не согласен с вашими рассуждениями о NULL, и говорить, что вам нужно изменить свое отношение к NULL, просто странно.

Я думаю, что isset () была разработана неправильно, isset() должна сообщить вам, была ли переменная установлена, и это не должно касаться фактического значения переменной.

Что делать, если вы проверяете значения, возвращаемые из базы данных, и один из столбцов имеет нулевое значение, вы все равно хотите знать, существует ли оно, даже если значение равно NULL ... нет, не доверяйте isset() здесь.

аналогично

$a = array ('test' => 1, 'hello' => NULL);

var_dump(isset($a['test']));   // TRUE
var_dump(isset($a['foo']));    // FALSE
var_dump(isset($a['hello']));  // FALSE

isset() должен был быть разработан для такой работы:

if(isset($var) && $var===NULL){....

таким образом, мы оставляем на усмотрение программиста проверку типов и не оставляем на усмотрение isset() предполагать, что его там нет, потому что значение равно NULL - это просто глупый дизайн

Я собираюсь быстро добавить к этому два цента.Одна из причин, по которой эта проблема сбивает с толку, заключается в том, что этот сценарий, похоже, возвращает тот же результат с сообщением об ошибке не на полную:

$a = null;
var_dump($a); // NULL
var_dump($b); // NULL

Исходя из этого результата, вы могли бы предположить, что разница между $a = null и не определяющий $b вообще - это ничто.

Вывод сообщения об ошибке Crank:

NULL

Notice: Undefined variable: b in xxx on line n
NULL

Примечание: он выдал ошибку неопределенной переменной, но выходное значение var_dump все еще NULL.

Очевидно, что PHP обладает внутренней способностью различать нулевую переменную и неопределенную переменную.Мне кажется, что должна быть встроенная функция для проверки этого.

Я думаю, что принятый ответ хорош по большей части, но если бы я собирался его реализовать, я бы написал для него оболочку.Как упоминалось ранее в этом ответе, Я должен согласиться, что на самом деле я не сталкивался с ситуацией, когда это было бы проблемой.Кажется, я почти всегда оказываюсь в сценарии, где мои переменные либо установлены и определены, либо нет (undefined, unset, null, blank и т.д.).Не хочу сказать, что подобная ситуация не возникнет в будущем, но поскольку это, похоже, довольно уникальная проблема, я не удивлен, что разработчики PHP не потрудились включить это.

Если я выполню следующее:

echo '<?php echo $foo; ?>' | php

Я получаю сообщение об ошибке:

PHP Notice:  Undefined variable: foo in /home/altern8/- on line 1

Если я выполню следующее:

echo '<?php if ( isset($foo) ) { echo $foo; } ?>' | php

Я не получаю сообщение об ошибке.

Если у меня есть переменная, которая должна быть установлена, я обычно делаю что-то вроде следующего.

$foo = isset($foo) ? $foo : null;

или

if ( ! isset($foo) ) $foo = null;

Таким образом, позже в скрипте я могу безопасно использовать $foo и знать, что он "установлен" и что по умолчанию он равен null.Позже я смогу if ( is_null($foo) ) { /* ... */ } если мне нужно, и я точно знаю, что переменная существует, даже если она равна null.

Полный документация isset читает немного больше, чем то, что было вставлено изначально.Да, он возвращает false для переменной, которая была ранее установлена, но теперь имеет значение null, но он также возвращает false, если переменная еще не была установлена (когда-либо) и для любой переменной, которая была помечена как unset.Он также отмечает, что нулевой байт ("\0") не считается нулевым и вернет значение true.

Определите, задана ли переменная.

Если переменная была отключена с помощью unset(), она больше не будет установлена.isset() вернет FALSE при проверке переменной , для которой было установлено значение NULL.Также обратите внимание, что нулевой байт ("\0") не эквивалентен константе PHP NULL .

Попробуйте использовать

unset($v)

Кажется, единственный раз, когда переменная не задана, это когда она специально не задана ($ v).Похоже, ваше значение слова "существование" отличается от определения PHP.NULL, безусловно, существует, это NULL.

Я должен сказать, что за все мои годы программирования на PHP я никогда не сталкивался с проблемой isset() возвращает false для нулевой переменной.OTOH, я столкнулся с проблемами с isset() сбой при нулевой записи массива - но array_key_exists() в этом случае работает корректно.

Для некоторого сравнения Icon явно определяет неиспользуемую переменную как возвращающую &null таким образом, вы используете тест is-null в Icon, чтобы также проверить наличие неустановленной переменной.Это действительно упрощает задачу.С другой стороны, Visual BASIC имеет несколько состояний для переменной, которая не имеет значения (Null, Empty, Nothing, ...), и вам часто приходится проверять наличие более одного из них.Известно, что это источник ошибок.

Согласно руководству по PHP для функции empty(), "Определите, считается ли переменная пустой.Переменная считается пустой, ЕСЛИ ОНА НЕ СУЩЕСТВУЕТ или если ее значение равно FALSE.empty() не генерирует предупреждение, если переменная не существует ". (Выделено мной.) Это означает, что функция empty() должна квалифицироваться как "лучший способ проверить существование переменной в PHP", согласно заголовку Вопроса.

Однако этого недостаточно, потому что функция empty() может быть обманута переменной, которая действительно существует и имеет значение NULL.

Я прерываю свой предыдущий ответ, чтобы представить что-то лучшее, потому что это менее громоздко, чем мой первоначальный ответ (который следует за этим перерывом для сравнения).

  function undef($dnc) //do not care what we receive
  { $inf=ob_get_contents();             //get the content of the buffer
    ob_end_clean();                     //stop buffering outputs, and empty the buffer
    if($inf>"")                         //if test associated with the call to this function had an output
    { if(false!==strpos($inf, "Undef"); //if the word "Undefined" was part of the output
        return true;                    //tested variable is undefined
    }
    return false;                       //tested variable is not undefined
  }

Две простые строки кода могут использовать приведенную выше функцию, чтобы определить, является ли переменная неопределенной:

  ob_start();                           //pass all output messages (including errors) to a buffer
  if(undef($testvar===null))            //in this case the variable being tested is $testvar

Вы можете дополнить эти две строки чем-нибудь подходящим, например, этим примером:

    echo("variable is undefined");
  else
    echo("variable exists, holding some value");

Я хотел поместить вызов ob_start() и ($testvar===null) внутри функции и просто передать переменную в функцию, но это не работает.Даже если вы попытаетесь использовать "передачу по ссылке" переменной в функцию, переменная СТАНЕТ определенной, и тогда функция никогда не сможет обнаружить, что ранее она была неопределенной.То, что представлено здесь, является компромиссом между тем, что я хотел сделать, и тем, что действительно работает.

Из предыдущего следует, что существует другой способ всегда избегать появления сообщения об ошибке "Неопределенная переменная".(Здесь предполагается, что предотвращение такого сообщения - это причина, по которой вы хотите проверить, не определена ли переменная.)

   function inst(&$v) { return; }  //receive any variable passed by reference; instantiates the undefined

Просто вызовите эту функцию, прежде чем что-то делать с вашим $testvar:

   inst($testvar);                //The function doesn't affect any value of any already-existing variable

Разумеется, значение вновь созданной переменной равно null!

(Прерывание заканчивается)

Итак, после некоторого изучения и экспериментов, вот что гарантированно сработает:

 function myHndlr($en, $es, $ef, $el)
 { global $er;
   $er = (substr($es, 0, 18) == "Undefined variable");
   return;
 }

 $er = false;
 if(empty($testvar))
 { set_error_handler("myHndlr");
   ($testvar === null);
   restore_error_handler();
 }
 if($er)  // will be 1 (true) if the tested variable was not defined.
 { ; //do whatever you think is appropriate to the undefined variable
 }

Объяснение:Переменная $er инициализируется значением по умолчанию "без ошибок".Определена "функция-обработчик".Если $testvar (переменная, которую мы хотим знать, является ли она неопределенной) проходит предварительный тест функции empty(), то мы проводим более тщательный тест.Мы вызываем функцию set_error_handler(), чтобы использовать ранее определенную функцию-обработчик.Затем мы выполняем простое сравнение идентификаторов с использованием $testvar, КОТОРОЕ, ЕСЛИ ОНО НЕ ОПРЕДЕЛЕНО, ВЫЗОВЕТ ОШИБКУ.Функция-обработчик фиксирует ошибку и специально проверяет, не является ли причиной ошибки тот факт, что переменная не определена.Результат помещается в переменную с информацией об ошибке $ er, которую мы можем позже протестировать, чтобы делать все, что захотим, в результате того, что мы точно знаем, был ли определен $testvar.Поскольку функция-обработчик нам нужна только для этой ограниченной цели, мы восстанавливаем исходную функцию обработки ошибок.Функция "myHndlr" должна быть объявлена только один раз;другой код может быть скопирован в любые подходящие места, для $testvar или любой другой переменной, которую мы хотим протестировать таким образом.

Я думаю, что единственное полноценное решение - это уведомления о сообщениях с

error_reporting(E_ALL); // Enables E_NOTICE

Но вам придется исправить все уведомления, генерируемые неопределенными переменными, константами, ключами массива, свойствами класса и другими.Как только вы это сделаете, вам не придется беспокоиться о разнице между null и not объявленными переменными, и двусмысленность исчезнет.

Включение сообщение об уведомлении возможно, это не во всех ситуациях хорошая альтернатива, но есть веские причины включить ее:

Почему я должен исправлять ошибки E_NOTICE?

В моем случае я больше года работал в проекте без этого, но привык быть осторожным при объявлении переменных, поэтому переход был быстрым.

Единственный способ узнать, определена ли переменная в текущей области видимости ($GLOBALS не заслуживает доверия) является array_key_exists( 'var_name', get_defined_vars() ).

Я предпочитаю использовать not empty как лучший метод проверки существования переменной, которая а) существует и б) не равна null.

if (!empty($variable)) do_something();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top