Best way to test for a variable's existence in PHP; isset() is clearly broken
Solution 1
If the variable you are checking would be in the global scope you could do:
array_key_exists('v', $GLOBALS)
Solution 2
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 isset
can 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 null
is the logical behaviour.
Real use cases (with solutions)
1. Array keys
Arrays can be treated like collections of variables, with unset
and isset
treating 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
.
The answer in this case, is to use array_key_exists()
instead of 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_exists
function, 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 null
values.
2. Object properties
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
).
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.
As with array keys, a solution for checking object properties is included in the language, called, reasonably enough, property_exists
.
Non-justifiable use cases, with discussion
3. register_globals
, and other pollution of the global namespace
The register_globals
feature 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 2000 and 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 global
keyword, or $GLOBALS
array.
Firstly, register_globals
itself is unlikely to unexpectedly produce a null
variable, since the GET, POST, and cookie values will always be strings (with ''
still returning true
from isset
), and variables in the session should be entirely under the programmer's control.
Secondly, pollution of a variable with the value null
is only an issue if this over-writes some previous initialization. "Over-writing" an uninitialized variable with null
would only be problematic if code somewhere else was distinguishing between the two states, so on its own this possibility is an argument against making such a distinction.
4. get_defined_vars
and compact
A few rarely-used functions in PHP, such as get_defined_vars
and compact
, allow you to treat variable names as though they were keys in an array. For global variables, the super-global array $GLOBALS
allows similar access, and is more common. These methods of access will behave differently if a variable is not defined in the relevant scope.
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.
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.
4a. Variable variables ($$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
.
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.
5. isset
is so much easier to type than 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 htmlspecialchars
so they would have an unusual number of characters...
Still, at least we're not writing Java, eh? ;)
6. Uninitialized variables have a type
The manual page on variable basics includes 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.
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 $a
and $b
in this code will end up as the integer 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
(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_function
can return null
, there's a possibility that the echo
won't be reached even though some_test
returned true
. The programmer's intention was to detect when $result
had never been set, but PHP does not allow them to do so.
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 $result
is 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.
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 $result
to a "terminal value" that some_function
can 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_function
has 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.
Thought experiment one: the very_null
constant
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_function
would not return it, so it would no longer be useful as a universal terminal value.
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 $result
that cannot be passed around, and can only be detected by specific built-in functions.
Thought experiment two: assignment counter
Another way of thinking about what the last if
is 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" about the variable, a bit like Perl's "variable tainting". So rather than isset
you might call it has_been_assigned_to
, and rather than unset
, reset_assignment_state
.
But if so, why stop at a boolean? What if you want to know how many times the test passed; you could simply extend your metadata to an integer and have get_assignment_count
and 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_null
constant, it would be useful only in very narrow circumstances, and would be similarly resistant to re-factoring.
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.
Solution 3
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.
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 === null
isset($a)
empty($a)
$a ? true : false
- …
All results are boolean, true
is printed and false
is omitted.
You can run the tests yourself, check this gist:
https://gist.github.com/mfdj/8165967
Solution 4
Explaining NULL, logically thinking
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.
Treat NULL properly
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".
An argument
Let's argue now. "But NULL is like saying 0 or FALSE or ''.
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. FALSE is the answer to yes or no,'' is the answer to the title someone submitted, and 0 is the answer to quantity or time etc. They ARE set as some type of answer/result which makes them valid as being set.
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.
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.
Feel free to quote this. It's off the top of my logical head :)
Solution 5
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().
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.
Related videos on Youtube
Comments
-
chazomaticus over 3 years
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 butNULL
.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$v
is not set) butis_null()
has a similar problem toisset()
: it returnsTRUE
on unset variables! It also appears that:@($v === NULL)
works exactly like
@is_null($v)
, so that's out, too.How are we supposed to reliably check for the existence of a variable in PHP?
Edit: there is clearly a difference in PHP between variables that are not set, and variables that are set to
NULL
:<?php $a = array('b' => NULL); var_dump($a);
PHP shows that
$a['b']
exists, and has aNULL
value. If you add: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 thesevar_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
UPDATE
statement, 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 aNULL
value, signified by passing aNULL
value in the array. You need a way to differentiate between an array key not existing, and an array's value being set toNULL
; that's the difference between not updating the column's value and updating the column's value toNULL
.Second, Zoredache's answer,
array_key_exists()
works correctly, for my above use case and for any global variables:<?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 callingarray_key_exists()
the official easiest way in PHP to truly check for the existence of a variable.(Only other case I can think of is for class properties, for which there's
property_exists()
, which, according to its docs, works similarly toarray_key_exists()
in that it properly distinguishes between not being set and being set toNULL
.)-
Theo Orphanos over 15 yearsYou can't check - but why do you need to?
-
Zoredache over 15 yearsYes, a good example for why you really need this would be helpful.
-
Ed S. over 15 yearsI agree. As far as you need to know, neither are set because they are both null. You can't use them for anything.
-
Josh Smeaton over 15 yearsInteresting observation, I wasn't aware of this. An answer has been found so this is redundant and incorrect - but I'd of probably used a placeholder value or an object for each row to make finding an unset property clearer.
-
Nathan Long about 14 yearsThere ARE reasons to differentiate between null and nonexistent. For example, you're building up an object to represent a row in a database table. For every column in the row, you create a private variable, accessible only via the object's getter method. Suppose a column value is null. Now how does that getter method know whether there's no such column in the table, or whether this object just has a null value there? Fortunately, in my case, the private variable is actually an entry in a private array, so I can use array_key_exists, but this is a real problem.
-
Halil Özgür over 13 yearsThe very same issue here for the same usage (db nulls). Having to use
array_key_exists()
is unintuitive. One more drop to my PHP cup... -
IMSoP almost 11 yearsI see no use cases in the edited question, or any of the answers and their comments, which actually justify having a variable which might or might not exist at runtime. Array keys and object properties can be treated as variables, and tested with
isset
, but their existence can also be verified witharray_key_exists()
andproperty_exists()
, so use cases involving them should be considered separately. -
chazomaticus almost 11 yearsEspecially in legacy setups, register_globals leads to global variables that might or might not exist at runtime.
-
IMSoP almost 11 years@chazomaticus Firstly, if they're NULL, it still doesn't matter. Secondly, if it does, we can chalk that up to one of the many things which were wrong with that feature, which has been removed from PHP completely. Justifying one bad idea with another doesn't convince me of a sensible use for non-existent variables.
-
chazomaticus almost 11 yearsIt's been removed from new versions of PHP, yes. Unfortunately, it's not gone from every deployment of PHP. Also, it seems like a pointless semantic detail to quibble about whether we're talking about array elements or variables. Regardless of what standards you think code should adhere to, it's useful to know how to work around an inconsistency in the PHP language.
-
IMSoP almost 11 years@chazomaticus But variables and array elements are fundamentally different things; just because you can do some of the same things with them doesn't mean they are or should be 100% interchangeable. There is no "inconsistency in the PHP language" here, just something you don't happen to like/understand. As for
register_globals
, I'm still struggling to think of a situation where even that would require such a distinction, since anything registered from the HTTP request would always be a string, notnull
. -
DimeCadmium almost 6 yearsThe real problem here is that PHP's database APIs treat database-NULL equivalently to PHP-NULL despite their being different things. (PHP-NULL is "uninitialized"; database-NULL is "initialized to empty")
-
-
chazomaticus over 15 yearsThis isn't a bad practice for simple scripts, but in complex (e.g. large OO) projects, it becomes infeasible. Also, as I said above, is_null() returns TRUE for variables that are not set, so there's really no reason to do what you're saying except to avoid a PHP warning.
-
Beau Simensen over 15 yearsFor well designed "large OO" projects, why would this be a problem at all? Why would you ever have $foo in a method body that may have not been set before its first usage?
-
chazomaticus over 15 yearsAh ha! NOW you're talkin'! How would you do that for, say, class properties?
-
chazomaticus over 15 yearsI'm not sure what you mean. If you have an array, with one element 'a', you don't have to unset() element 'b' for element 'b' not to exist in PHP, it just doesn't exist. Same thing with e.g. global variables, which you can think of as elements of the $GLOBALS array.
-
chazomaticus over 15 yearsBut I agree that a variable with a NULL value does in fact exist.
-
Henrik Opel over 13 yearsAs a variation, if the check needs to work for local scope variables as well, on can do a
$defined_vars = get_defined_vars();
and then test viaarray_key_exists('v', $defined_vars);
. -
curtisdf about 12 yearsGreat answer. So many times I see people ranting about how they hate this or that feature of a language. But they seem to be assuming that "if it doesn't do it MY way, then it's broken." Yes, there are bad design decisions. But there are also very close-minded developers!
-
Halil Özgür almost 12 years
empty()
does not check if the variable is null, it checks if it's false-y, e.g. not one of the""
(an empty string),0
(0 as an integer),0.0
(0 as a float),"0"
(0 as a string),NULL
,FALSE
,array()
(an empty array) and$var;
(a variable declared, but without a value). Say you have a required radio field in a form with two inputs with the values0
and1
. If you useempty()
for validation and the user selects the0
one, you'd inadvertently error out "required field cannot be empty". See the manual php.net/manual/en/function.empty.php -
enrey almost 11 yearsThere IS a HUGE difference between unset variable and variable===null. One doesn't exist, the other has value null. Arguments that null means no value simply aren't true. Null IS A VALUE of type null. It's perfectly valid value and there's no reason for php to treat it as non-existing value, which it sadly does. It would be OK, if non-existing variables were null and every existing variable was not-null and assigning null into variable would unset it. But there are MANY situations, where functions return null as actual value. Then we're screwed up, because there's no bloody way to test for it.
-
IMSoP almost 11 years@enrey If a function returns NULL, and you're testing that return value, then you've put it somewhere, so you know that the container exists. Other than debugging, there should never be a case where a variable - as opposed to an array key or object property - "might or might not have been set yet".
-
IMSoP almost 11 yearsYour example is not checking the existence of a variable, but of an array key. A solution to that exists, in the form of
array_key_exists
. You should never be in a situation where you don't know at runtime if an actual variable exists. -
enrey almost 11 years@IMSoP what brings you to that idea? Didn't you ever run into a situation, where a function is in the middle of complex loops and conditions and it might or might not have been run, and it's return value was/wasn't assigned to a variable, and testing on variable existence is the only thing to help you... Well, not really, since you can't test for set/not-set variable in php, you had to add that
$my_function_has_run = true;
right next to your function call. Well, that doesn't make the language less turing-complete. But it surely does make it more anoying. -
IMSoP almost 11 years@enrey That sounds a lot like debugging to me. If that check is necessary in the final code, you've got some pretty wacky logic. Remember that in many languages, a variable either exists or not based on declaration in a particular scope, so such a test would be meaningless.
-
IMSoP almost 11 years@chazomaticus Well, you should never be in a situation where register_globals is turned on, so I stand by that statement.
-
chazomaticus almost 11 yearsOh, I agree. Still, not everyone can control where their code is deployed. It's useful to have information for every situation, whether it's how things "should" be or not.
-
chazomaticus almost 11 yearsVery good points, though not exactly an answer to the question.
-
IMSoP almost 11 yearsTo the explicit question "How are we supposed to reliably check for the existence of a variable in PHP?" my answer is "you're not, and here's why". Both this answer and greatbigmassive's also answer the implicit question "why does
isset()
behave that way?". -
IMSoP almost 11 years@chazomaticus If your problem is
register_globals
, then your answer is not a change toisset()
. The PHP manual mentions "it really is generally a good programming practice to initialize variables first", which solvesregister_globals
at design-time rather than run-time. There is also an FAQ entry giving anunregister_globals()
function to deal with it at run-time. -
enrey almost 11 years@IMSoP true, but php doesn't follow logic of other languages. It has its own world, and in it's own world, variable is created when it's assigned to, there's no declaration for it. Besides, even in other languages, you can test variable existence. I'm not saying null being equivalent to unset variable is somehow big problem, it's just a small anoyance in a language, that has been built purely from small anoyances. So, whatever. Let's get back to business.
-
IMSoP almost 11 years@enrey See my answer for the reason an uninitialized variable could still be considered to "exist". You can even assign to another variable from it, and you get
null
. It would be far more annoying to have a second constant representing not-null-but-read-from-an-unitialized-variable, which would be the consistent result ofisset()
making such a distinction. -
enrey almost 11 yearsI know we're "not supposed" to check variable existence in php, hell, there's not even any real way to check it. I'm not going to write code which deppends on it, because it's not possible in php. That's a limitation of php. There clearly is a difference between non-set and null variable, yet php provides no ways to distinguish those. Yet lot of meta functionality depends on it internaly: reading non-existing var produces notice,
isset($a['x'])
will tell you false ifx
is null, yet it will show up incount($a)
..compact
will work on all set variables, includingnulls
, and so on. -
IMSoP almost 11 years@enrey Careful, once again some of your examples are using arrays, for which we have array_key_exists. The vast majority of functionality treats an uninitialized variable as equal to null, so it's perfectly reasonable not to distinguish between the two states. The notice is a hint that you should change your code to initialize it explicitly for better code, not because it makes any difference in itself. As for
compact
, that's more like code reflection than anything you'd see in every day code. -
chazomaticus almost 11 yearsThis answer is flawed in one major way: in OO programming, null is the logical choice to mean "no object". For example, in unexceptional circumstances when a function can return an object or no object, null is the obvious choice. Technically in PHP, false or any other value considered false in boolean context could be used, but then you're losing some semantic purity. Thus, null is a perfectly reasonable value to initialize a variable to that should hold an object eventually, because it is relevant to what it's intended to become.
-
chazomaticus almost 11 yearsIMSoP, the PHP manual actually makes it clear that uninitialized variables can have any number of types, depending on the context, so it's not correct to say "the vast majority of functionality..." without knowing what the code is doing. Also, nobody's arguing that you shouldn't initialize variables before using them. The question is simply wondering, given a situation where there's some ambiguity about whether a variable was declared, how can that be resolved.
-
enrey almost 11 years@IMSoP
key
is 3 characters long,isset
has 5 characters,array_key_exists
has 16. Think about it. Plus,array_key_exists
complains if the array itself does not exist. Therefore checking index that's at the bottom of huge tree structure the proper way is going to introduce massive amount of boilerplate, all just for checking one key existence. Again, i'm not saying it's unusable, it's just introducing unnecessary pain. But I don't care, I'm running away from php anyway. -
IMSoP almost 11 years@chazomaticus 1) I have never said that there aren't valid uses for
null
; I have said that there aren't valid uses for "uninitialized" as a value/state distinct fromnull
. 2) I hadn't seen that description of uninitialized variables before, but note that in practice they consistently behave the same as anull
value being coerced in the same situation. I stand by the claim that except in very esoteric situations, there is not and should not be a meaningful distinction between the two states. -
IMSoP almost 11 years@enrey I'm not really sure what the length of function names has to do with anything being discussed here. The argument for a recursive
array_key_exists
(i.e. one that performs multiple existence checks rather than checking a normal variable against a particular test) is an interesting one; I guess you can use the@
"shut up operator", but that does always seem like a hack. It's still not a use case for a function that detects uninitialized bare variables, rather than array keys, though. -
chazomaticus almost 11 yearsIMSoP, I think you're confused. My comment about null was in response to this answer, not you. And I'll repeat myself in regard to your claim: nobody's denying that! This conversation has gone far beyond being useful.
-
IMSoP almost 11 years@chazomaticus Apologies, I did misunderstand that point. It is a valid clarification of the answer that
null
might be a valid initialization state. Of course, that would then be a constant in the code, so there would be no need to check if it had happened or not at runtime. -
Piet Bijl over 10 yearsNULL is perfectly valid for setting artibrary variables, if the value has yet to be determined that is. Argument for not setting a $var as NULL is thus broken. So is ISSET()
-
Denis Pshenov over 10 yearsThis answer is fundamentally flawed as demonstrated by enrey and others.
-
M Miller over 10 yearsPHP doesn't, but I wouldn't say most other languages don't. Most any language that declares variables will throw an error if a variable hasn't been declared, but you can set them to
NULL
. Semantically,NULL
should mean "no resource," but not defining a variable is a programmer error. -
IMSoP about 10 years@MMiller Sure, but writing code that follows one path in the case of "no resource" and a different path in the case of "programmer error" is fairly nonsensical. If you want to detect undeclared variables during debugging, use a static analysis tool, like you would to find potential errors in any language.
-
IMSoP about 10 yearsIf the intention is to avoid a warning that your variables haven't been declared, then the solution is to fix your code to declare them properly. Your
inst
function is basically like the@
error-suppression operator: "I know I'm doing something wrong here, but I just want that message to go away, without actually changing the operation of my code in any way". -
IMSoP about 10 yearsThe detection methods, on the other hand, are ingenious, but I am still of the firm belief that you should never have any use for them other than to echo the very warning messages that they're catching. (You should probably clarify that your output buffering version requires error_reporting set high and display_errors to be turned on.)
-
Arild almost 10 yearsThis looks a bit ugly to me, but in the case where you're actually checking an array element, it makes much more sense:
isset($foo[$bar])
becomesarray_key_exists($bar, $foo)
-
Chris Middleton over 9 yearsAs long as PHP throws errors for undefined variables, but not for null, then there is a difference. If null and undefined were really the same concept, then PHP should assume default undefined/undeclared variables to null and never throw an error, but no one wants that because it's a development nightmare. Null and undefined may not really be different in the context of value semantics, but they are very different when it comes to writing clear and debuggable code.
-
Pacerier over 9 years@MMiller, Cool, how did you even thought of this.
-
M Miller over 9 yearsI end up looking at it a little differently now that I use JavaScript because there are more states. If you say
alert(x);
whenx
was never declared, it throws a reference error. If you dovar x; alert(x);
you getundefined
.undefined
is a different state fromnull
. For example, many programs use an options hash, e.g. the options for a lightbox script might be:var options = { onClose: function () { ... }, centerHorizontally: true }
. IfonClose
were set tonull
, that might mean do nothing, whereas undefined (or absent) implies use the default setting. -
Beejor about 9 years@ChrisMiddleton Exactly! In most languages, there's a big difference between null/nil and undefined. The former is a data type, meaning you can assign it to variables (it basically means "empty, but not an empty string or zero or false"). The latter is a read-only keyword that evaluates to true in the case of an identifier that isn't found. The difference is why JavaScript has two different keywords, and why stricter languages like Basic don't let you set Integers/Booleans/Strings to Null (only Variants or Objects).
-
IMSoP about 9 years@MMiller As with so many examples here, your JS options example is of a key in some particular object/hash, not a bare variable. Thus the equivalent code in PHP would use array_key_exists or property_exists, not isset.
-
IMSoP about 9 yearsThe warning on undefined variables is a hint to the programmer that they have done something wrong in the code. Outside debugging (for which there are tools outside the language), there should never be a need for a program to detect such a state, because the programmer should always know what variables they are declaring.
-
M Miller about 9 years@IMSoP Yes, I know. This comment was simply in response to the answer to point out that there is a purpose to having a case when something doesn't exist versus when it is null. I didn't intend my comment to be a response to the OP's question, but rather a rebuttal against this particular answer.
-
IMSoP about 9 years@MMiller But it doesn't work as a rebuttal, because the statement in the answer is explicitly about "a variable not existing", and your counter-example is about an object property / hash key not existing. The distinction between these cases is not just incidental.
-
M Miller about 9 yearsYup, you're right, my mistake. Although the same would still apply if I did
var onClose = options.onClose; if (onClose === undefined) { ... } else if (onClose === null) { ... }
-
Andrew about 9 yearsRegarding classes and properties, sadly property_exists() doesn't work when the property is array, for example: Class{ public $property = array() }. Throws an error.
-
IMSoP about 9 years@Andrew Seems to work fine for me: 3v4l.org/TnAY5 Care to provide a complete example?
-
Andrew about 9 yearsyeah it seems to work fine, something wrong was with my setup. Sorry for the false alarm :)
-
Hugo Zink over 8 yearsThere are plenty of reasons to have variables set to null. What if I'm getting data from a database and I want to see if the column exists but is simply null (which happens all the time)?
-
Hugo Zink over 8 years"If you read from a variable that doesn't currently have an entry, PHP considers that variable to have the value NULL." This is false. An undefined variable is simply undefined. It may return null when you try to access it, but that's irrelevant.
-
IMSoP over 8 years@HugoZink Irrelevant to what? Any test you do of the value of an undefined variable will tell you that the value is
null
. Whether that value exists before you look at it is a question for philosophers, but as far as any observable behaviour is concerned the value is consistentlynull
. -
alexw over 8 years
property_exists
seems promising, except for this: > The property_exists() function cannot detect properties that are magically accessible using the __get magic method. -
ToolmakerSteve over 7 years@HugoZink - IMHO you've misunderstood the discussion. No one suggested that variables should not be set to null. The only question is whether/when there need to be TWO different concepts:
null
vs.has never been set to anything, not even to null
. This lengthy answer intends to demonstrate that when you need to make that distinction, there is some way to do so in php [except in limited cases, that there is disagreement about how important those are]. Though the code needed is different, depending on what entity you are examining. -
ToolmakerSteve over 7 years@MMiller - indeed that is a better example. Still, after 20+ years programming in strict languages, the situations where I needed a distinctions between
undefined
andnull
are so rare that I don't miss it. IMHO, the main use forundefined
is "programmer error in a non-strict language". In a strict language, if I need a distinct state forclient did not state a value
, then I declare a value appropriate to the situation, and test for it. Worst case, have to add a separate flag variable. But doing that rarely is better than having to ALWAYS cope with TWO different non-value states!! -
Stephan Vierkant over 7 yearsI think that's what many other people said before, or am I wrong?
-
Brilliand about 7 years@alexw Variables "created" via __get indeed don't exist. __get is arbitrary code used as a fallback for nonexistent variables, that can return whatever it wants regardless of whether any relevant data was ever stored.
-
Hugo Zink almost 7 yearsIf you have a magic __get method, you will probably want to have a magic __isset method as well, which you could use.
-
jave.web almost 7 yearsThis is not probably relevant in reality, but ...
get_defined_vars()
+array_key_exists
WILL NOT test if variable was really declared or not, it's just a way how to detect that variable was "initialized" withnull
... Just a simple declaration -$a;
is a valid code, though this method would result infalse
:) But as I said, this is more of a "fun fact", that may concern a few random C people :-) -
Rik Schaaf over 6 yearsMaybe out of the scope of this question, but you might want to add
"0"
to the table, for completeness and clarity of theempty
operation