在 PHP 中测试变量是否存在的最佳方法;isset() 明显坏了
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/418066/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to test for a variable's existence in PHP; isset() is clearly broken
提问by chazomaticus
From the isset()docs:
isset() will return FALSE if testing a variable that has been set to NULL.
Basically, isset()doesn't check for whether the variable is set at all, but whether it's set to anything but NULL.
基本上,isset()根本不检查是否设置了变量,而是检查它是否设置为除NULL.
Given that, what's the best way to actually check for the existence of a variable? I tried something like:
鉴于此,实际检查变量是否存在的最佳方法是什么?我试过类似的东西:
if(isset($v) || @is_null($v))
(the @is necessary to avoid the warning when $vis not set) but is_null()has a similar problem to isset(): it returns TRUEon unset variables! It also appears that:
(这@是在$v未设置时避免警告所必需的)但is_null()有类似的问题isset():它返回未TRUE设置的变量!似乎还有:
@($v === NULL)
works exactly like @is_null($v), so that's out, too.
和 完全一样@is_null($v),所以也一样。
How are we supposed to reliably check for the existence of a variable in PHP?
我们应该如何可靠地检查 PHP 中变量的存在?
Edit: there is clearly a difference in PHP between variables that are not set, and variables that are set to NULL:
编辑:PHP 中未设置的变量和设置为的变量之间显然存在差异NULL:
<?php
$a = array('b' => NULL);
var_dump($a);
PHP shows that $a['b']exists, and has a NULLvalue. If you add:
PHP 显示$a['b']存在,并且具有NULL值。如果添加:
var_dump(isset($a['b']));
var_dump(isset($a['c']));
you can see the ambiguity I'm talking about with the isset()function. Here's the output of all three of these var_dump()s:
你可以看到我所说的isset()函数的歧义。这是所有这三个的输出var_dump()s:
array(1) {
["b"]=>
NULL
}
bool(false)
bool(false)
Further edit: two things.
进一步编辑:两件事。
One, a use case. An array being turned into the data of an SQL UPDATEstatement, where the array's keys are the table's columns, and the array's values are the values to be applied to each column. Any of the table's columns can hold a NULLvalue, signified by passing a NULLvalue in the array. You needa way to differentiate between an array key not existing, and an array's value being set to NULL; that's the difference between not updating the column's value and updating the column's value to NULL.
一,用例。将数组转化为 SQLUPDATE语句的数据,其中数组的键是表的列,数组的值是要应用于每一列的值。表的任何列都可以保存一个NULL值,通过NULL在数组中传递一个值来表示。您需要一种方法来区分不存在的数组键和设置为 的数组值NULL;这就是不更新列的值和将列的值更新为NULL.
Second, Zoredache's answer, array_key_exists()works correctly, for my above use case and for any global variables:
其次,Zoredache的答案,array_key_exists()工作正常,我上面的用例和任何全局变量:
<?php
$a = NULL;
var_dump(array_key_exists('a', $GLOBALS));
var_dump(array_key_exists('b', $GLOBALS));
outputs:
输出:
bool(true)
bool(false)
Since that properly handles just about everywhere I can see there being any ambiguity between variables that don't exist and variables that are set to NULL, I'm calling array_key_exists()the official easiest way in PHP to truly check for the existence of a variable.
自那正确处理几乎无处不在,我可以看到那里是不存在的,并且被设置成变量变量之间的任何含糊之处NULL,我打电话给array_key_exists()在PHP官方最简单的方法真正检查变量的存在。
(Only other case I can think of is for class properties, for which there's property_exists(), which, according to its docs, works similarly to array_key_exists()in that it properly distinguishes between not being set and being set to NULL.)
(我能想到的唯一其他情况是对于类属性,property_exists()根据其文档,array_key_exists()它的工作原理与类属性类似,因为它正确区分了未设置和设置为NULL。)
采纳答案by Zoredache
If the variable you are checking would be in the global scope you could do:
如果您正在检查的变量在全局范围内,您可以执行以下操作:
array_key_exists('v', $GLOBALS)
回答by IMSoP
Attempting to give an overview of the various discussions and answers:
试图概述各种讨论和答案:
There is no single answer to the question which can replace all the ways issetcan be used.Some use cases are addressed by other functions, while others do not stand up to scrutiny, or have dubious value beyond code golf. Far from being "broken" or "inconsistent", other use cases demonstrate why isset's reaction to nullis the logical behaviour.
这个问题没有单一的答案可以代替所有isset可以使用的方法。一些用例由其他功能解决,而其他用例则经不起,或者在代码高尔夫之外具有可疑的价值。远非“损坏”或“不一致”,其他用例展示了为什么对逻辑行为isset的反应null。
Real use cases (with solutions)
实际用例(带解决方案)
1. Array keys
1. 数组键
Arrays can be treated like collections of variables, with unsetand issettreating them as though they were. However, since they can be iterated, counted, etc, a missing value is not the same as one whose value is null.
数组可以像变量的集合一样对待,unset并isset像对待它们一样对待它们。但是,由于它们可以迭代、计数等,因此缺失值与值为 的值不同null。
The answer in this case, is to use array_key_exists()instead of isset().
在这种情况下,答案是使用array_key_exists()代替isset()。
Since this is takes the array to check as a function argument, PHP will still raise "notices" if the array itself doesn't exist. In some cases, it can validly be argued that each dimension should have been initialised first, so the notice is doing its job. For other cases, a "recursive" array_key_existsfunction, which checked each dimension of the array in turn, would avoid this, but would basically be the same as @array_key_exists. It is also somewhat tangential to the handling of nullvalues.
由于这是将要检查的数组作为函数参数,因此如果数组本身不存在,PHP 仍会引发“通知”。在某些情况下,可以合理地争辩说每个维度都应该首先被初始化,因此通知正在发挥作用。对于其他情况,array_key_exists依次检查数组每个维度的“递归”函数可以避免这种情况,但基本上与@array_key_exists. 它也与null值的处理有些相关。
2. Object properties
2. 对象属性
In the traditional theory of "Object-Oriented Programming", encapsulation and polymorphism are key properties of objects; in a class-based OOP implementation like PHP's, the encapsulated properties are declared as part of the class definition, and given access levels (public, protected, or private).
在“面向对象编程”的传统理论中,封装和多态是对象的关键属性;在像 PHP 这样基于类的 OOP 实现中,封装的属性被声明为类定义的一部分,并被赋予访问级别(public、protected、 或private)。
However, PHP also allows you to dynamically add properties to an object, like you would keys to an array, and some people use class-less objects (technically, instances of the built in stdClass, which has no methods or private functionality) in a similar way to associative arrays. This leads to situations where a function may want to know if a particular property has been added to the object given to it.
但是,PHP 还允许您动态地向对象添加属性,就像您添加数组的键一样,并且有些人以类似的方式使用无类对象(从技术上讲,内置 的实例,stdClass没有方法或私有功能)关联数组的方法。这导致函数可能想知道特定属性是否已添加到给定对象的情况。
As with array keys, a solution for checking object properties is included in the language, called, reasonably enough, property_exists.
与数组键一样,该语言中包含了一种用于检查对象属性的解决方案,称为property_exists.
Non-justifiable use cases, with discussion
不合理的用例,有讨论
3. register_globals, and other pollution of the global namespace
3. register_globals、等对全局命名空间的污染
The register_globalsfeature added variables to the global scope whose names were determined by aspects of the HTTP request (GET and POST parameters, and cookies). This can lead to buggy and insecure code, which is why it has been disabled by default since PHP 4.2, released Aug 2000and removed completely in PHP 5.4, released Mar 2012. However, it's possible that some systems are still running with this feature enabled or emulated. It's also possible to "pollute" the global namespace in other ways, using the globalkeyword, or $GLOBALSarray.
该register_globals功能向全局范围添加了变量,其名称由 HTTP 请求的各个方面(GET 和 POST 参数以及 cookie)确定。这可能会导致错误和不安全的代码,这就是为什么自2000 年 8 月发布的 PHP 4.2起默认禁用它并在2012 年 3 月发布的 PHP 5.4 中完全删除的原因。但是,某些系统可能仍在启用或模拟此功能的情况下运行。也可以使用global关键字或$GLOBALS数组以其他方式“污染”全局命名空间。
Firstly, register_globalsitself is unlikely to unexpectedly produce a nullvariable, since the GET, POST, and cookie values will always be strings (with ''still returning truefrom isset), and variables in the session should be entirely under the programmer's control.
首先,register_globals它本身不太可能意外地产生一个null变量,因为 GET、POST 和 cookie 值将始终是字符串(''仍然true从返回isset),并且会话中的变量应该完全在程序员的控制之下。
Secondly, pollution of a variable with the value nullis only an issue if this over-writes some previous initialization. "Over-writing" an uninitialized variable with nullwould only be problematic if code somewhere else was distinguishing between the two states, so on its own this possibility is an argument againstmaking such a distinction.
其次,null如果这覆盖了一些先前的初始化,则变量与值的污染只是一个问题。null只有在其他地方的代码区分这两种状态时,“覆盖”未初始化的变量才会有问题,因此这种可能性本身就是反对进行这种区分的论据。
4. get_defined_varsand compact
4.get_defined_vars和compact
A few rarely-used functions in PHP, such as get_defined_varsand compact, allow you to treat variable names as though they were keys in an array. For global variables, the super-global array $GLOBALSallows similar access, and is more common. These methods of access will behave differently if a variable is not defined in the relevant scope.
PHP 中一些很少使用的函数,例如get_defined_varsand compact,允许您将变量名视为数组中的键。对于全局变量,超全局数组$GLOBALS允许类似的访问,并且更常见。如果变量未在相关作用域中定义,这些访问方法的行为将有所不同。
Once you've decided to treat a set of variables as an array using one of these mechanisms, you can do all the same operations on it as on any normal array. Consequently, see 1.
一旦您决定使用其中一种机制将一组变量视为一个数组,您就可以对它执行与任何普通数组相同的所有操作。因此,见 1。
Functionality that existed only to predict how these functions are about to behave (e.g. "will there be a key 'foo' in the array returned by get_defined_vars?") is superfluous, since you can simply run the function and find out with no ill effects.
仅用于预测这些函数将如何运行的功能(例如“在由 返回的数组中会有一个键 'foo'get_defined_vars吗?”)是多余的,因为您可以简单地运行该函数并找出没有不良影响的结果。
4a. Variable variables ($$foo)
4a. 可变变量 ( $$foo)
While not quite the same as functions which turn a set of variables into an associative array, most cases using "variable variables"("assign to a variable named based on this other variable") can and should be changed to use an associative array instead.
虽然与将一组变量转换为关联数组的函数不太一样,但大多数使用“变量变量”(“分配给基于此其他变量命名的变量”)的情况可以并且应该改为使用关联数组.
A variable name, fundamentally, is the label given to a value by the programmer; if you're determining it at run-time, it's not really a label but a key in some key-value store. More practically, by not using an array, you are losing the ability to count, iterate, etc; it can also become impossible to have a variable "outside" the key-value store, since it might be over-written by $$foo.
变量名,从根本上说,是程序员赋予一个值的标签;如果您在运行时确定它,它实际上并不是一个标签,而是某个键值存储中的一个键。更实际的是,通过不使用数组,您将失去计数、迭代等的能力;在键值存储“外部”拥有变量也可能变得不可能,因为它可能被$$foo.
Once changed to use an associative array, the code will be amenable to solution 1. Indirect object property access (e.g. $foo->$property_name) can be addressed with solution 2.
一旦更改为使用关联数组,代码将适用于解决方案 1。间接对象属性访问(例如$foo->$property_name)可以通过解决方案 2 解决。
5. issetis so much easier to type than array_key_exists
5.isset打字比打字容易多了array_key_exists
I'm not sure this is really relevant, but yes, PHP's function names can be pretty long-winded and inconsistent sometimes. Apparently, pre-historic versions of PHP used a function name's length as a hash key, so Rasmus deliberately made up function names like htmlspecialcharsso they would have an unusual number of characters...
我不确定这是否真的相关,但是是的,PHP 的函数名称有时可能非常冗长且不一致。显然,PHP 的史前版本使用函数名的长度作为哈希键,所以 Rasmus 故意编造函数名,htmlspecialchars这样它们就会有不寻常的字符数......
Still, at least we're not writing Java, eh? ;)
不过,至少我们不是在写 Java,嗯?;)
6. Uninitialized variables have a type
6. 未初始化的变量有一个类型
The manual page on variable basicsincludes this statement:
Uninitialized variables have a default value of their type depending on the context in which they are used
未初始化的变量具有其类型的默认值,具体取决于使用它们的上下文
I'm not sure whether there is some notion in the Zend Engine of "uninitialized but known type" or whether this is reading too much into the statement.
我不确定 Zend 引擎中是否存在“未初始化但已知类型”的概念,或者这是否对语句读得太多了。
What is clear is that it makes no practical difference to their behaviour, since the behaviours described on that page for uninitialized variables are identical to the behaviour of a variable whose value is null. To pick one example, both $aand $bin this code will end up as the integer 42:
很明显,这对它们的行为没有实际影响,因为该页面上描述的未初始化变量的行为与值为 的变量的行为相同null。举一个例子,在这段代码中,$a和$b最终都是整数42:
unset($a);
$a += 42;
$b = null;
$b += 42;
(The first will raise a notice about an undeclared variable, in an attempt to make you write better code, but it won't make any difference to how the code actually runs.)
(第一个会引发关于未声明变量的通知,试图让您编写更好的代码,但它不会对代码的实际运行方式产生任何影响。)
99. Detecting if a function has run
99. 检测函数是否已运行
(Keeping this one last, as it's much longer than the others. Maybe I'll edit it down later...)
(把这个留到最后,因为它比其他的要长得多。也许我稍后会编辑它......)
Consider the following code:
考虑以下代码:
$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!';
}
If some_functioncan return null, there's a possibility that the echowon't be reached even though some_testreturned true. The programmer's intention was to detect when $resulthad never been set, but PHP does not allow them to do so.
如果some_function可以返回null,则有可能echo即使some_test返回也无法到达true。程序员的意图是检测何时$result从未设置过,但 PHP 不允许他们这样做。
However, there are other problems with this approach, which become clear if you add an outer loop:
但是,这种方法还有其他问题,如果您添加外部循环,这些问题就会变得很明显:
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!';
}
}
Because $resultis never initialized explicitly, it will take on a value when the very first test passes, making it impossible to tell whether subsequent tests passed or not. This is actually an extremely common bug when variables aren't initialised properly.
因为$result从未显式初始化,所以当第一次测试通过时,它将采用一个值,从而无法判断后续测试是否通过。当变量没有正确初始化时,这实际上是一个非常常见的错误。
To fix this, we need to do something on the line where I've commented that something's missing. The most obvious solution is to set $resultto a "terminal value" that some_functioncan never return; if this is null, then the rest of the code will work fine. If there is no natural candidate for a terminal value because some_functionhas an extremely unpredictable return type (which is probably a bad sign in itself), then an additional boolean value, e.g. $found, could be used instead.
为了解决这个问题,我们需要在我评论说缺少某些东西的地方做一些事情。最明显的解决方案是设置$result一个some_function永远不会返回的“终端值” ;如果是这样null,那么其余的代码将正常工作。如果由于some_function具有极其不可预测的返回类型(这本身可能是一个不好的迹象)而没有终端值的自然候选者,则可以使用额外的布尔值,例如$found。
Thought experiment one: the very_nullconstant
思想实验一:very_null常数
PHP could theoretically provide a special constant - as well as null- for use as a terminal value here; presumably, it would be illegal to return this from a function, or it would be coerced to null, and the same would probably apply to passing it in as a function argument. That would make this very specific case slightly simpler, but as soon as you decided to re-factor the code - for instance, to put the inner loop into a separate function - it would become useless. If the constant could be passed between functions, you could not guarantee that some_functionwould not return it, so it would no longer be useful as a universal terminal value.
PHP 理论上可以提供一个特殊的常量 - 以及null- 在这里用作终端值;据推测,从函数返回 this 是非法的,或者它会被强制转换为null,同样的情况可能适用于将它作为函数参数传入。这将使这个非常特殊的情况稍微简单一些,但是一旦您决定重新分解代码 - 例如,将内部循环放入一个单独的函数中 - 它就会变得无用。如果常量可以在函数之间传递,您不能保证some_function不会返回它,因此它不再作为通用终端值有用。
The argument for detecting uninitialised variables in this case boils down to the argument for that special constant: if you replace the comment with unset($result), and treat that differently from $result = null, you are introducing a "value" for $resultthat cannot be passed around, and can only be detected by specific built-in functions.
在这种情况下检测未初始化变量的论点归结为该特殊常量的论点:如果您将注释替换为unset($result),并将其与 区别对待$result = null,则您将引入一个“值”,$result因为它无法传递,并且只能是由特定的内置函数检测。
Thought experiment two: assignment counter
思想实验二:赋值计数器
Another way of thinking about what the last ifis asking is "has anything made an assignment to $result?" Rather than considering it to be a special value of $result, you could maybe think of this as "metadata" aboutthe variable, a bit like Perl's "variable tainting". So rather than issetyou might call it has_been_assigned_to, and rather than unset, reset_assignment_state.
思考最后一个if问题的另一种方式是“有没有分配给什么东西$result?” 与其将其视为 的特殊值$result,您还可以将其视为关于变量的“元数据” ,有点像 Perl 的“变量污染”。所以,而不是isset你可能会称之为has_been_assigned_to,而不是unset,reset_assignment_state。
But if so, why stop at a boolean? What if you want to know how many timesthe test passed; you could simply extend your metadata to an integer and have get_assignment_countand reset_assignment_count...
但如果是这样,为什么要停留在布尔值上?如果您想知道测试通过了多少次怎么办?您可以简单地将您的元数据扩展为一个整数,并拥有get_assignment_count和reset_assignment_count...
Obviously, adding such a feature would have a trade-off in complexity and performance of the language, so it would need to be carefully weighed against its expected usefulness. As with a very_nullconstant, it would be useful only in very narrow circumstances, and would be similarly resistant to re-factoring.
显然,添加这样的特性会在语言的复杂性和性能方面进行权衡,因此需要仔细权衡它的预期用途。与very_null常量一样,它仅在非常狭窄的情况下才有用,并且同样抵抗重构。
The hopefully-obvious question is why the PHP runtime engine should assume in advance that you want to keep track of such things, rather than leaving you to do it explicitly, using normal code.
希望显而易见的问题是,为什么 PHP 运行时引擎应该事先假设您想要跟踪这些事情,而不是让您使用普通代码明确地去做。
回答by Mark Fox
Sometimes I get a little lost trying to figure out which comparison operation to use in a given situation. isset()only applies to uninitialized or explicitly null values. Passing/assigning null is a great way to ensure a logical comparison works as expected.
有时我在试图找出在给定情况下使用哪种比较操作时会有点迷茫。isset()仅适用于未初始化或显式空值。传递/分配 null 是确保逻辑比较按预期工作的好方法。
Still, it's a little difficult to think about so here's a simple matrix comparing how different values will be evaluated by different operations:
尽管如此,考虑一下还是有点困难,所以这里有一个简单的矩阵,比较不同的操作将如何评估不同的值:
| | ===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 |
To fit the table I compressed the labels a bit:
为了适应表格,我稍微压缩了标签:
$a;refers to a declared but unassigned variable- everything else in the first column refers to an assigned value, like:
$a = null;$a = [];$a = 0;- …
- the columns refer to comparison operations, like:
$a === nullisset($a)empty($a)$a ? true : false- …
$a;引用已声明但未赋值的变量- 第一列中的所有其他内容都引用了指定的值,例如:
$a = null;$a = [];$a = 0;- …
- 列指的是比较操作,例如:
$a === nullisset($a)empty($a)$a ? true : false- …
All results are boolean, trueis printed and falseis omitted.
所有结果都是布尔值,true被打印并被false省略。
You can run the tests yourself, check this gist:
https://gist.github.com/mfdj/8165967
你可以自己运行测试,检查这个要点:https:
//gist.github.com/mfdj/8165967
回答by Matijs
You can use the compact language construct to test for the existence of a null variable. Variables that do not exist will not turn up in the result, while null values will show.
您可以使用紧凑语言构造来测试是否存在空变量。不存在的变量不会出现在结果中,而会显示空值。
$x = null;
$y = 'y';
$r = compact('x', 'y', 'z');
print_r($r);
// Output:
// Array (
// [x] =>
// [y] => y
// )
In the case of your example:
就您的示例而言:
if (compact('v')) {
// True if $v exists, even when null.
// False on var $v; without assignment and when $v does not exist.
}
Of course for variables in global scope you can also use array_key_exists().
当然,对于全局范围内的变量,您也可以使用 array_key_exists()。
B.t.w. personally I would avoid situations like the plague where there is a semantic difference between a variable not existing and the variable having a null value. PHP and most other languages just does not think there is.
顺便说一句,我个人会避免像瘟疫这样的情况,即不存在的变量和具有空值的变量之间存在语义差异。PHP 和大多数其他语言只是认为没有。
回答by greatbigmassive
Explaining NULL, logically thinking
解释NULL,逻辑思考
I guess the obvious answer to all of this is... Don't initialise your variables as NULL, initalise them as something relevant to what they are intended to become.
我想所有这一切的明显答案是......不要将您的变量初始化为 NULL,将它们初始化为与它们打算成为的内容相关的东西。
Treat NULL properly
正确对待NULL
NULL should be treated as "non-existant value", which is the meaning of NULL. The variable can't be classed as existing to PHP because it hasn't been told what type of entity it is trying to be. It may aswell not exist, so PHP just says "Fine, it doesn't because there's no point to it anyway and NULL is my way of saying this".
NULL 应该被视为“不存在的值”,这就是 NULL 的含义。变量不能被归类为 PHP 的现有变量,因为它没有被告知它试图成为哪种类型的实体。它也可能不存在,所以 PHP 只是说“好吧,它不存在,因为无论如何它都没有意义,NULL 是我的表达方式”。
An argument
一个论点
Let's argue now. "But NULL is like saying 0 or FALSE or ''.
现在我们来争论。“但是 NULL 就像说 0 或 FALSE 或 ''。
Wrong, 0-FALSE-'' are all still classed as empty values, but they ARE specified as some type of value or pre-determined answer to a question. FALSEis the answer to yes or no,''is the answer to the title someone submitted, and 0is the answer to quantity or time etc. They ARE set as some type of answer/result which makes them valid as being set.
错误,0-FALSE-'' 仍然被归类为空值,但它们被指定为某种类型的值或问题的预先确定的答案。FALSE是是或否的答案,''是某人提交的标题的答案,0是数量或时间等的答案。它们被设置为某种类型的答案/结果,这使得它们被设置为有效。
NULL is just no answer what so ever, it doesn't tell us yes or no and it doesn't tell us the time and it doesn't tell us a blank string got submitted. That's the basic logic in understanding NULL.
NULL 只是没有答案,它没有告诉我们是或否,也没有告诉我们时间,也没有告诉我们提交了一个空字符串。这就是理解 NULL 的基本逻辑。
Summary
概括
It's not about creating wacky functions to get around the problem, it's just changing the way your brain looks at NULL. If it's NULL, assume it's not set as anything. If you are pre-defining variables then pre-define them as 0, FALSE or "" depending on the type of use you intend for them.
这不是创建古怪的函数来解决问题,它只是改变你的大脑看待 NULL 的方式。如果它是 NULL,假设它没有被设置为任何东西。如果您要预定义变量,则根据您打算使用它们的类型将它们预定义为 0、FALSE 或“”。
Feel free to quote this. It's off the top of my logical head :)
随意引用这个。这超出了我的逻辑头脑:)
回答by greatbigmassive
Object properties can be checked for existence by property_exists
可以通过property_exists检查对象属性是否存在
Example from a unit test:
来自单元测试的示例:
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");
}
}
回答by IMSoP
As an addition to greatbigmassive's discussion of what NULL means, consider what "the existence of a variable" actually means.
作为greatbigmassive 对NULL 含义的讨论的补充,请考虑“变量的存在”的实际含义。
In many languages, you have to explicitly declare every variable before you use it; this may determine its type, but more importantly it declares its scope. A variable "exists" everywhere in its scope, and nowhere outside it - be that a whole function, or a single "block".
在许多语言中,您必须在使用之前显式声明每个变量;这可能决定了它的类型,但更重要的是它声明了它的作用域。变量“存在”在其范围内的任何地方,而在其范围之外的任何地方都“存在”——无论是整个函数还是单个“块”。
Within its scope, a variable assigns some meaning to a labelwhich you, the programmer, have chosen. Outside its scope, that label is meaningless (whether you use the same label in a different scope is basically irrelevant).
在它的范围内,一个变量为您(程序员)选择的标签分配了一些含义。在它的范围之外,那个标签是没有意义的(你是否在不同的范围内使用相同的标签基本上是无关紧要的)。
In PHP, variables do not need to be declared- they come to life as soon as you need them. When you write to a variable for the first time, PHP allocates an entry in memory for that variable. If you read from a variable that doesn't currently have an entry, PHP considers that variable to have the value NULL.
在 PHP 中,不需要声明变量- 只要您需要它们,它们就会立即生效。当您第一次写入变量时,PHP 会在内存中为该变量分配一个条目。如果您从当前没有条目的变量中读取,PHP 会认为该变量具有值NULL。
However, automatic code quality detectors will generally warn you if you use a variable without "initialising" it first. Firstly, this helps detect typos, such as assigning to $thingIdbut reading from $thing_id; but secondly, it forces you to consider the scope over which that variable has meaning, just as a declaration would.
但是,如果您使用一个变量而没有先“初始化”它,自动代码质量检测器通常会警告您。首先,这有助于检测拼写错误,例如分配给$thingId但读取自$thing_id;但其次,它迫使您考虑该变量具有意义的范围,就像声明一样。
Any code that cares whether a variable "exists" is part of the scope of that variable- whether or not it has been initialised, you as a programmer have given that label meaning at that point of the code. Since you're using it, it must in some sense "exist", and if it exists, it must have an implicit value; in PHP, that implicit value is null.
任何关心变量是否“存在”的代码都是该变量作用域的一部分——无论它是否已被初始化,作为程序员的你已经在代码的那个点赋予了该标签的含义。既然你在使用它,它就必须在某种意义上“存在”,如果它存在,它必须有一个隐含的值;在 PHP 中,隐含值是null.
Because of the way PHP works, it is possible to write code that treats the namespace of existent variables not as a scope of labels you have given meaning to, but as some kind of key-value store. You can, for instance, run code like this: $var = $_GET['var_name']; $$var = $_GET['var_value'];. Just because you can, doesn't mean it's a good idea.
由于 PHP 的工作方式,可以编写代码来将现有变量的命名空间视为您赋予意义的标签范围,而不是某种键值存储。你可以,例如,运行这样的代码:$var = $_GET['var_name']; $$var = $_GET['var_value'];。仅仅因为你可以,并不意味着这是一个好主意。
It turns out, PHP has a much better way of representing key-value stores, called associative arrays. And although the values of an array can be treated like variables, you can also perform operations on the array as a whole. If you have an associative array, you can test if it contains a key using array_key_exists().
事实证明,PHP 有一种更好的表示键值存储的方法,称为关联数组。尽管可以将数组的值视为变量,但您也可以对整个数组执行操作。如果您有关联数组,则可以使用array_key_exists().
You can also use objects in a similar way, dynamically setting properties, in which case you can use property_exists()in exactly the same way. Of course, if you define a class, you can declare which properties it has- you can even choose between public, private, and protectedscope.
您还可以以类似的方式使用对象,动态设置属性,在这种情况下,您可以property_exists()以完全相同的方式使用。当然,如果你定义一个类时,你可以声明其性能已经-你甚至可以选择public,private和protected范围。
Although there is a technicaldifference between a variable (as opposed to an array key, or an object property) that hasn't been initialised (or that has been explicitly unset()) and one whose value is null, any code that considers that difference to be meaningfulis using variables in a way they're not meant to be used.
虽然有技术的可变(相对于阵列键,或一个对象的属性)之间的差异还未被初始化(或者是已经明确地unset()和一个其值)null,即认为差异是任何代码有意义以不打算使用的方式使用变量。
回答by Salman A
issetchecks if the variable is set and, if so, whether its valueis not NULL. The latter part is (in my opinion) not within the scope of this function. There is no decent workaround to determine whether a variable is NULL because it is not setor because it is explicitly set to NULL.
isset检查变量是否已设置,如果已设置,则其值是否不为 NULL。后一部分(在我看来)不在此功能的范围内。没有合适的解决方法来确定变量是 NULL是因为它没有设置还是因为它被显式设置为 NULL。
Here is one possible solution:
这是一种可能的解决方案:
$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
Other workaround is to probe the output of get_defined_vars():
其他解决方法是探测以下输出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
回答by Robbie Averill
I'm going to add a quick two cents to this. One reason this issue is confusing is because this scenario seems to return the same result with error reporting noton full:
我要快速添加两分钱。这个问题令人困惑的一个原因是因为这种情况似乎返回了相同的结果,但错误报告没有完整:
$a = null;
var_dump($a); // NULL
var_dump($b); // NULL
You could assume from this result that the difference between $a = nulland not defining $bat all is nothing.
你可以从这个结果中假设$a = null和根本不定义之间的区别$b是什么。
Crank error reporting up:
曲柄错误报告:
NULL
Notice: Undefined variable: b in xxx on line n
NULL
Note:it threw an undefined variable error, but the output value of var_dumpis still NULL.
注意:它抛出了一个未定义的变量错误,但 的输出值var_dump仍然是NULL。
PHP obviously does have an internal ability to distinguish between a null variable and an undefined variable. It seems to me that there should be a built in function to check for this.
PHP 显然具有区分空变量和未定义变量的内部能力。在我看来,应该有一个内置函数来检查这个。
I think the accepted answer is good for the most part, but if I was going to implement it I would write a wrapper for it. As previously mentioned in this answer, I have to agree that I haven't actually encountered a situation where this has been a problem. I seem to almost always end up in a scenario where my variables are either set and defined, or they aren't (undefined, unset, null, blank, etc). Not to say that a situation like this won't occur in future, but as it seems to be quite a unique issue I'm not surprised that the PHP devs haven't bothered to put this in.
我认为接受的答案在很大程度上是好的,但是如果我要实现它,我会为它编写一个包装器。正如之前在这个答案中提到的,我必须同意我实际上没有遇到过这种情况。我似乎几乎总是以这样一种情况结束:我的变量要么被设置和定义,要么没有(未定义、未设置、空、空白等)。并不是说将来不会发生这样的情况,但由于这似乎是一个非常独特的问题,我对 PHP 开发人员没有费心将其放入并不感到惊讶。
回答by Christof Coetzee
I don't agree with your reasoning about NULL, and saying that you need to change your mindset about NULL is just weird.
我不同意你对 NULL 的推理,说你需要改变你对 NULL 的心态是很奇怪的。
I think isset() was not designed correctly, isset() should tell you if the variable has been set and it should not be concerned with the actual value of the variable.
我认为 isset() 设计不正确,isset() 应该告诉你变量是否已经设置,它不应该关心变量的实际值。
What if you are checking values returned from a database and one of the columns have a NULL value, you still want to know if it exists even if the value is NULL...nope dont trust isset() here.
如果您正在检查从数据库返回的值并且其中一列具有 NULL 值,您仍然想知道它是否存在,即使该值为 NULL...不,这里不信任 isset()。
likewise
同样地
$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() should have been designed to work like this:
isset() 应该被设计成这样工作:
if(isset($var) && $var===NULL){....
this way we leave it up to the programmer to check types and not leave it up to isset() to assume its not there because the value is NULL - its just stupid design
这样我们就让程序员来检查类型,而不是让 isset() 假设它不存在,因为值是 NULL - 这只是愚蠢的设计

![php 警告:fopen() [function.fopen]:文件名不能为空](/res/img/loading.gif)