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

187

Из 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.

Во- вторых, ответ 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.)

chazomaticus
источник
Вы не можете проверить - но зачем вам это нужно?
слишком много php
12
NULL имеет очень специфическое значение в PHP, и это совершенно отдельная концепция от того, установлена ​​переменная или нет.
chazomaticus
33
Есть причины отличать нуль от несуществующего. Например, вы создаете объект для представления строки в таблице базы данных. Для каждого столбца в строке вы создаете приватную переменную, доступную только через метод getter объекта. Предположим, что значение столбца равно нулю. Как этот метод получателя узнает, нет ли такого столбца в таблице или этот объект просто имеет нулевое значение? К счастью, в моем случае приватная переменная на самом деле является записью в приватном массиве, поэтому я могу использовать array_key_exists, но это реальная проблема.
Натан Лонг
1
Это было удалено из новых версий PHP, да. К сожалению, это не исчезло из каждого развертывания PHP. Кроме того, кажется бессмысленной семантической деталью, чтобы спорить о том, говорим ли мы об элементах массива или переменных. Независимо от того, какие стандарты, по вашему мнению, должен соблюдать код, полезно знать, как обойти несоответствия в языке PHP.
chazomaticus
2
@chazomaticus Но переменные и элементы массива - это принципиально разные вещи ; просто потому, что вы можете делать с ними одни и те же вещи, не означает, что они являются или должны быть на 100% взаимозаменяемыми. Здесь нет «несоответствия в языке PHP», просто то, что вам не нравится / не нравится. Что касается register_globals, я все еще изо всех сил пытаюсь придумать ситуацию, когда даже это потребовало бы такого различия, поскольку все, что зарегистрировано из запроса HTTP, всегда будет строкой, а не null.
IMSoP

Ответы:

97

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

array_key_exists('v', $GLOBALS) 
Zoredache
источник
3
Ах, ха! ТЕПЕРЬ ты говоришь! Как бы вы это сделали, скажем, для свойств класса?
chazomaticus
22
В качестве варианта, если проверка должна работать и для локальных переменных области действия, можно выполнить a, $defined_vars = get_defined_vars();а затем выполнить тестирование с помощью array_key_exists('v', $defined_vars);.
Хенрик Опель
1
Это выглядит немного уродливо для меня, но в случае, когда вы на самом деле проверяете элемент массива, это имеет гораздо больше смысла: isset($foo[$bar])становитсяarray_key_exists($bar, $foo)
Arild
property_existsкажется многообещающим, за исключением этого:> Функция property_exists () не может обнаружить свойства, которые магически доступны, используя магический метод __get.
alexw
@alexw Переменные, «созданные» через __get, действительно не существуют. __get - это произвольный код, используемый в качестве запасного варианта для несуществующих переменных, который может возвращать все, что захочет, независимо от того, были ли когда-либо сохранены соответствующие данные.
Brilliand