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


С isset() docs:

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

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

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

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

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

@($v === NULL)

работает точно так же, как @is_null($v), так что тоже.

как мы должны надежно проверить наличие переменной в PHP?


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

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

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

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

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

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

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

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

второе, Zoredache это,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.)

17 177

17 ответов:

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

array_key_exists('v', $GLOBALS) 

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

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

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

1. Ключи массива

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

ответ в этом случае -использовать array_key_exists() вместо isset().

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

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

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

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

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

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

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

The register_globals функция добавила переменные в глобальную область, имена которых определялись аспектами HTTP-запроса (параметры GET и POST, а также файлы cookie). Это может привести к багги и небезопасный код, поэтому он был отключен по умолчанию с PHP 4.2, выпущен Aug 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. Неинициализированные переменные имеют типа

The страница руководства по переменным основам включает в себя следующее утверждение:

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

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

ясно, что это не имеет никакого практического значения для их поведения, поскольку поведение, описанное на этой странице для неинициализированных переменных, идентично поведению переменной, значение которой 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, вы могли бы подумать об этом как о "метаданных"о переменная, немного похожая на "переменную tainting" Perl. Так что вместо isset вы можете назвать это has_been_assigned_to, а чем unset,reset_assignment_state.

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

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

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

иногда я немного теряюсь, пытаясь выяснить, какую операцию сравнения использовать в данной ситуации. 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().

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

объясняя нуль, логически думая

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

лечить NULL правильно

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

аргумент

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

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

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

резюме

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

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

свойства объекта можно проверить на существование с помощью property_exists

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

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, рассмотрим, что на самом деле означает" существование переменной".

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

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

в 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 потому что он не установлен или так он явно установлен в 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) ) { /* ... */ } если мне нужно и знаю уверен, что переменная существует, даже если она равна нулю.

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

определить установлена ли переменная.

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

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

unset($v)

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

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

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

согласно руководству PHP для функции empty (), " определите, считается ли переменная пустой. Переменная считается пустой, если она не существует или если ее значение равно FALSE. пустой () не создает предупреждение, если переменная не существует."(Мой акцент.) Это означает, что функция 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) внутри функции и просто передать переменную в функцию, но она не работает. Даже если вы попытаетесь использовать" pass by reference " переменной для функции, переменная становится определенной, и тогда функция никогда не сможет обнаружить, что она ранее не была определена. То, что здесь представлено, является компромиссом между тем, что я хотел сделать, и тем, что на самом деле работает.

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

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

Я думаю, что единственным полным решением является уведомления отчет С

error_reporting(E_ALL); // Enables E_NOTICE

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

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

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

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

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

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

if (!empty($variable)) do_something();