在 PHP 中测试变量是否存在的最佳方法; isset ()显然已经被破坏了

来自 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。)

149859 次浏览

如果我运行以下命令:

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,但是如果变量尚未设置(曾经) ,并且对于任何标记为未设置的变量,它也返回 false。它还注意到 NULL 字节(“0”)不被认为是 NULL,并将返回 true。

确定是否设置了变量。

< p > 如果一个变量被取消设置 如果不设置() ,则不再设置它。 如果测试 a,isset ()将返回 FALSE 设置为 NULL 的变量。 还要注意,NULL 字节(“0”)是 不等同于 PHP NULL 不变

如果要检查的变量在全局范围内,那么可以这样做:

array_key_exists('v', $GLOBALS)

我必须说,在我多年的 PHP 编程生涯中,我从未遇到过 isset()返回 null 变量 false 的问题。OTOH,我遇到过 isset()在空数组条目上失败的问题-但是在这种情况下 array_key_exists()可以正常工作。

为了进行一些比较,Icon 显式地将未使用的变量定义为返回 &null,因此您可以使用 Icon 中的 is-null 测试来检查未设置的变量。这确实让事情变得简单了。另一方面,VisualBASIC 对于没有值的变量有多种状态(Null、 Empty、 Nothing、 ...) ,并且您通常需要检查其中的多个状态。众所周知,这是一个错误的来源。

尝试使用

unset($v)

似乎变量唯一没有设置的时候就是它被特别取消设置的时候($v)。听起来你对“存在”的定义与 PHP 的定义不同。NULL 当然是存在的,它是 NULL。

对象属性可以通过 属性 _ 存在检查是否存在

单元测试的例子:

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");
}
}

您可以使用紧凑语言结构来测试空变量的存在。不存在的变量将不会出现在结果中,而将显示空值。

$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 _ vis ()。

就我个人而言,我会避免这样的情况: 不存在的变量和具有空值的变量之间存在语义差异。PHP 和大多数其他语言并不认为有。

解释为空,逻辑思考

我想对这一切最明显的答案是... ..。 不要将你的变量初始化为 NULL,而是将它们初始化为与它们的意图相关的东西

正确对待 NULL

应将 NULL 视为“不存在值”,这是 NULL 的意思。 该变量不能被归类为存在于 PHP 中,因为它还没有被告知它正在尝试成为什么类型的实体。它也可能不存在,所以 PHP 只是说: “好吧,它不存在,因为它没有任何意义,而 NULL 是我表达这一点的方式。”。译注:

吵架

让我们现在讨论。“但是 NULL 就像说0或者 FALSE 或者”。

错误,0-FALSE-”仍然被归类为空值,但它们被指定为某种类型的值或预先确定的问题答案。假的是是或否的答案,''是某人提交的标题的答案,0是数量或时间等的答案。它们被设置为某种类型的答案/结果,这使得它们作为设置是有效的。

NULL 就是没有答案,所以它不会告诉我们是或否,也不会告诉我们时间,也不会告诉我们提交了一个空字符串。这是理解 NULL 的基本逻辑。

摘要

这不是创建古怪的函数来解决问题,而是改变你的大脑看待 NULL 的方式。如果是 NULL,假设它没有设置为任何值。如果您是预定义变量,那么根据您打算使用它们的类型,将它们预定义为0、 FALSE 或“”。

欢迎引用。 这是我逻辑上的第一反应

说你需要改变你对 NULL 的心态是很奇怪的。

我认为 isset ()的设计不正确,isset ()应该告诉您是否已经设置了变量,它不应该与变量的实际值有关。

如果您正在检查从数据库返回的值,并且其中一个列的值为 NULL,那么即使该值为 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)存在,b)不为空。

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

isset检查变量是否已设置,如果已设置,则检查其 价值是否为 NULL。后一部分(在我看来)不在这个函数的范围之内。没有合适的解决方案来确定变量是 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 意味着什么的讨论的补充,考虑一下“变量的存在”实际上意味着什么。

这可以确定它的类型,但更重要的是它声明了它的 范围。一个变量在它的作用域中无处不在,而在它之外的任何地方都不存在——无论是一个完整的函数,还是一个单独的“块”。

你,程序员,选择的 在其作用域内,变量为标签赋予某种意义。在其作用域之外,该标签是没有意义的(是否在不同的作用域中使用相同的标签基本上是不相关的)。

它们在你需要它们的时候就会活过来。当您第一次写入变量时,PHP 会在内存中为该变量分配一个条目。如果从一个当前没有条目的变量中读取,PHP 认为该变量的值为 NULL

但是,如果您使用的变量没有首先“初始化”它,自动代码质量检测器通常会发出警告。首先,这有助于检测输入错误,例如赋值给 $thingId,但是从 $thing_id读取; 但是其次,它强制您考虑变量具有意义的范围,就像声明一样。

任何关心变量是否“存在”的代码都是该变量作用域的一部分-无论它是否已经被初始化,你作为一个程序员已经给了这个标签的意义在那一点的代码。因为您正在使用它,所以它必须在某种意义上“存在”,如果它存在,它必须有一个隐式值; 在 PHP 中,这个隐式值是 null

由于 PHP 的工作方式,我们可以编写代码,将存在变量的名称空间不当作您已经赋予意义的标签范围,而是当作某种键值存储。例如,您可以像这样运行代码: $var = $_GET['var_name']; $$var = $_GET['var_value'];你可以,并不意味着这是个好主意。

事实证明,PHP 有一种更好的方式来表示键值存储,称为关联数组。虽然数组的值可以像变量一样处理,但是您也可以对整个数组执行操作。如果您有一个关联数组,您可以使用 < a href = “ http://php.net/array _ key _ publications”rel = “ nofollow norefrer”> array_key_exists() 来测试它是否包含一个密钥。

您还可以以类似的方式使用对象,动态设置属性,在这种情况下,您可以以完全相同的方式使用 property_exists()。当然,如果定义一个类,则可以声明它具有哪些属性-您甚至可以选择之间的 publicprivate,和 protected范围。

虽然一个变量(与数组键或对象属性相对)没有被初始化(或者显式地为 unset())和一个值为 null的变量之间存在 技术上的差异,但是任何认为这种差异是 有意义的代码都是在以一种不应该使用的方式使用变量。

试图概述各种讨论和答复:

这个问题没有一个单一的答案,可以取代所有的方式 isset可以使用。有些用例是由其他函数处理的,而其他用例经不起仔细审查,或者除了代码高尔夫之外,其他用例的价值值值得怀疑。其他用例远非“破碎”或“不一致”,而是展示了为什么 issetnull的反应是合乎逻辑的行为。

实际用例(包括解决方案)

1. 数组键

数组可以像变量集合一样处理,unsetisset将它们视为变量集合。但是,由于它们可以被迭代、计数等,所以缺少的值与值为 null的值是不一样的。

在这种情况下,答案是 使用 < a href = “ http://php.net/array _ key _ publications”rel = “ noReferrer”> ABC0 而不是 isset()

因为它将数组作为函数参数进行检查,所以如果数组本身不存在,PHP 仍然会发出“通知”。在某些情况下,可以有效地论证每个维度应该首先被初始化,因此通知正在发挥其作用。对于其他情况,依次检查数组的每个维度的“递归”array_key_exists函数可以避免这种情况,但基本上与 @array_key_exists相同。它也与 null值的处理有些相关。

2. 对象属性

在传统的“面向对象程序设计”理论中,封装和多态是对象的关键属性,在基于类的面向对象实现(比如 PHP)中,封装的属性被声明为类定义的一部分,并且给定访问级别(publicprotectedprivate)。

然而,PHP 也允许您动态地向对象添加属性,就像您可以键入数组一样,而且有些人使用无类对象(技术上,stdClass中内置的实例,它没有方法或私有功能)的方式类似于关联数组。这会导致函数可能想知道是否已将特定属性添加到给它的对象中的情况。

与数组键一样,语言中包含了一个检查对象属性的解决方案,这个解决方案被合理地调用为 < a href = “ http://php.net/property _ vis”rel = “ norefrer”> property_exists

不合理的用例,并进行讨论

3. register_globals和其他全局名称空间的污染

register_globals特性向全局范围添加了变量,这些变量的名称由 HTTP 请求的各个方面(GET 和 POST 参数以及 cookie)决定。这可能导致错误和不安全的代码,这就是为什么自 2000年8月发布的 PHP 4.2以来默认禁用它,并在 PHP 5.4,2012年3月发布中完全删除它的原因。但是,有些系统可能仍然在启用或模拟此特性的情况下运行。还可以使用 global关键字或 $GLOBALS数组以其他方式“污染”全局名称空间。

首先,register_globals本身不太可能意外地生成 null变量,因为 GET、 POST 和 cookie 值总是字符串(''仍然从 isset返回 true) ,会话中的变量应该完全由程序员控制。

其次,值为 null的变量的污染只有在覆盖了以前的初始化时才是问题。用 null“覆盖”一个未初始化的变量只有在其他地方的代码区分这两种状态时才会出现问题,所以这种可能性本身就是 反对进行这种区分的一个参数。

4. get_defined_varscompact

PHP 中一些很少使用的函数,如 get_defined_varscompact,允许您将变量名视为数组中的键。对于全局变量,超全局数组 $GLOBALS允许类似的访问,并且更常见。如果没有在相关作用域中定义变量,则这些访问方法的行为将不同。

一旦决定使用这些机制之一将一组变量视为一个数组,就可以对其执行与任何普通数组相同的操作。因此,请参见1。

仅用于预测这些函数将如何运行的功能(例如,“ get_defined_vars返回的数组中是否有一个关键字‘ foo’?”)是多余的,因为你可以简单地运行函数,并找出没有不良影响。

变量($$foo)

虽然与将一组变量转换为关联数组的函数不完全相同,但大多数情况下,使用 “可变变量”(“指定一个基于另一个变量命名的变量”)的情况可以而且应该改为使用关联数组。

从根本上说,变量名是程序员给一个值的标签; 如果您在运行时确定它,那么它实际上不是一个标签,而是某个键-值存储中的一个键。更实际的情况是,如果不使用数组,您将失去计数、迭代等功能; 在键值存储区之外存储变量也是不可能的,因为它可能被 $$foo覆盖。

一旦更改为使用关联数组,代码将适用于解决方案1。解决方案2可以处理间接对象属性访问(例如 $foo->$property_name)。

5. issetarray_key_exists简单得多

我不确定这是否真的相关,但是是的,PHP 的函数名有时可能非常冗长和不一致。显然,PHP 的史前版本使用函数名的长度作为散列键,所以 Rasmus 故意编造了像 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,那么即使 some_test返回 true,也有可能无法到达 echo。程序员的目的是检测从未设置 $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从未显式初始化过,所以当第一个测试通过时,它将接受一个值,这使得无法判断后续测试是否通过。当变量没有被正确地初始化时,这实际上是一个非常常见的 bug。

为了解决这个问题,我们需要做一些事情,在这一行中,我已经注释说有一些东西丢失了。最明显的解决方案是将 $result设置为 some_function永远不能返回的“终端值”; 如果这是 null,那么代码的其余部分就可以正常工作。如果由于 some_function有一个极不可预测的返回类型(这本身可能是一个坏符号) ,因此没有天然的候选终端值,那么可以使用一个额外的布尔值,例如 $found

思想实验一: very_null常数

PHP 理论上可以提供一个特殊的常量——以及 null——作为这里的终端值; 假设,从函数返回这个常量是非法的,或者它将被强制为 null,同样的情况也可能适用于作为函数参数传递它。这将使这个非常特殊的情况稍微简单一些,但是一旦您决定重构代码——例如,将内部循环放入一个单独的函数中——它就会变得毫无用处。如果常数可以在函数之间传递,那么您就不能保证 some_function不会返回它,因此它将不再作为通用终端值使用。

在这种情况下,检测未初始化变量的参数可以归结为特殊常量的参数: 如果用 unset($result)替换注释,并将其与 $result = null区别对待,那么就为 $result引入了一个不能传递的“值”,并且只能通过特定的内置函数来检测。

思维实验二: 作业计数器

另一种思考最后一个 if问题的方式是“有没有什么东西被赋值给 $result?”与其认为它是 $result的一个特殊值,不如把它看作变量 关于的“元数据”,有点像 Perl 的“变量污染”。所以你可以称它为 has_been_assigned_to,而不是 unsetreset_assignment_state

但是如果是这样,为什么要停留在布尔值上呢?如果您想知道 多少次测试通过了,那么可以简单地将元数据扩展为一个整数,并使用 get_assignment_countreset_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;引用一个已声明但未赋值的变量
  • < li > 第一列中的所有其他内容都指向一个赋值,如:
    • $a = null;
    • $a = [];
    • $a = 0;
    • ...
    < li > 列引用比较操作,比如:
    • $a === null
    • isset($a)
    • empty($a)
    • $a ? true : false
    • ...

所有结果都是布尔型的,打印 true,省略 false

你可以自己运行测试,检查这个要点: < br/> https://gist.github.com/mfdj/8165967

根据空()函数的 PHP 手册,“确定一个变量是否被认为是空的。如果一个变量不存在,或者它的值等于 FALSE,则该变量被认为是空的。如果变量不存在,则 void ()不会生成警告。”(我的重点)这意味着,根据标题“问题”,void ()函数应该符合“在 PHP 中测试变量存在性的最佳方法”的标准。

但是,这还不够好,因为 void ()函数可能会被一个确实存在并且设置为 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)的调用放在函数中,然后简单地将变量传递给函数,但是它不起作用。即使您尝试使用“通过引用传递”的变量到函数,变量 BECOMES 定义,然后函数永远不能检测到它以前未定义。这里展示的是我想做的和真正有效的两者之间的妥协。

前面的内容意味着还有另一种方法可以避免遇到“未定义变量”错误消息。(这里的假设是,阻止这样的消息是您想要测试变量是否未定义的原因。)

   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 (我们希望知道是否未定义的变量)通过了初步的 void ()函数测试,那么我们将进行更彻底的测试。我们调用 set _ error _ handler ()函数来使用先前定义的 Handler 函数。然后我们做一个简单的身份比较,包括 $testvar,如果没有定义会触发一个错误。Handlder 函数捕获错误,并专门测试错误的原因是否是变量未定义的事实。结果放置在错误信息变量 $er 中,稍后我们可以测试该变量来执行任何我们想要的操作,以确定是否定义了 $testvar。因为我们只需要处理程序函数来实现这个有限的用途,所以我们还原了原始的错误处理函数。“ myHndlr”函数只需要声明一次; 其他代码可以复制到任何适当的位置,对于 $testvar 或任何其他我们希望以这种方式测试的变量。

我再加两分钱。这个问题令人困惑的一个原因是,这个场景似乎返回相同的结果,错误报告 没有是完整的:

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

从这个结果可以假设,$a = null和根本没有定义 $b之间没有什么区别。

曲柄错误报告:

NULL


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

它抛出了一个未定义的变量错误,但 var_dump的输出值仍然是 NULL

PHP 显然具有区分空变量和未定义变量的内部能力。在我看来,应该有一个内置的功能来检查这一点。

我认为公认的答案在大多数情况下是好的,但是如果我要实现它,我会为它编写一个包装器。正如前面提到的 在这个答案中,我必须承认,我实际上还没有遇到过这样的问题。我似乎总是在一个场景中结束,我的变量要么被设置和定义,要么没有(未定义,未设置,空,空,等等)。并不是说将来不会出现这样的情况,但是因为这似乎是一个非常独特的问题,所以 PHP 开发人员没有费心把它放进去我并不感到惊讶。

我认为唯一完整的解决方案是 报告通知书

error_reporting(E_ALL); // Enables E_NOTICE

但是您必须修复所有由未定义变量、常量、数组键、类属性等生成的通知。一旦您完成了这项工作,您就不必担心 null 变量和未声明变量之间的差异,这样模糊性就消失了。

启用 通知书报告可能不是所有情况下的一个好选择,但有充分的理由启用它:

为什么我要修复 E _ NOTICE 错误

在我的例子中,在一个没有它的项目中工作了一年多,但是在声明变量时常常很小心,所以转换起来很快。

知道变量是否在当前范围内定义($GLOBALS不可信)的唯一方法是 array_key_exists( 'var_name', get_defined_vars() )