« Why Interfaces Rock | Peer Review: You Have Not Because You Ask Not (Requests & Responses) » |
One of the most confusing things for new programmers (and it even trips me up sometimes) is how to test for boolean conditions in code. As developers, we want to develop code that never emits notices or warnings, and PHP gets a bit antsy when we develop code that utilizes uninitialized variables. Lucky for us, PHP makes it easy to test for these variables without getting these notices.
PHP (like most languages) evaluates a logical argument left to right. For an AND condition, both conditions have to be true; PHP stops evaluating if it finds any condition untrue; that means that we can use isset() or empty() as the first parameter in an if statement, and avoid raising notices.
For those who don’t know: isset() and empty() are two language constructs in PHP. A language construct is not a function, but a special language tool (like an if-else statement or a while loop), and in this case isset() and empty() allow us to test variables for various conditions.
When To Use isset()
The construct isset() tests for whether or not a variable exists in the present scope. If the variable has been defined in the global scope, in any form (except null), this will return true. Otherwise, it will return false.
You should use isset() when you want to determine if you wish to test that variable for another condition. For example:
<?php if (isset($var) && $var > 6) { // do something here } if(isset($var) && $var === false) { // Do something else here. } ?>
If the variable is not set, isset() will return false. This will cause the first condition to be false, and PHP will not evaluate the second condition (which would emit an error).
When To Use empty()
The empty() construct works in a very similar fashion to isset() but has a difference: you want to use empty() when you care whether the variable has a value that would evaluate to true.
Consider the following code sample:
$variable = false; if(isset($variable)) { echo 'This variable is set.'; } if(!empty ($variable)) { echo 'This variable is not empty.'; }
In the first example, isset() tells us that the variable is in fact set in the current scope. But in the second test, the variable is deemed empty, because the value is false. This is an extremely useful tool, but one that can be dangerous! False is an absolutely valid value (for example, you might set configuration options to false) but you may want to execute whatever is inside an if statement even if the value is false.
Additionally, empty strings, the values “false”, null and 0 all resolve to “true” when you use empty(). This can create problems that you’ll want to avoid, for example:
<?php $string = "A string to test."; $var = strpos($string, "A string"); // Returns integer 0 as the position it was found. if(empty($var)) { echo 'Not found!'; } ?>
This example illustrates a case where using empty() would create a problem. strpos() returns 0 if it finds the needle at the beginning of the string (position 0). However, if it does not find it at all, it returns false. However, false and 0 both evaluate to empty! This code sample would be better rewritten as follows:
<?php $string = "A string to test."; $var = strpos($string, "A string"); // Returns integer 0 as the position it was found. if(isset($var) && $var === false) { echo 'Not found!'; } ?>
The use of the isset() means that we know the variable exists but we don’t evaluate its value yet. The second condition evaluates whether or not the variable is actually false (three equals signs compare type as well as value).
In a nutshell, the simple rules of empty() and isset() are this: use isset() if you only care whether the variable exists in the current scope, and use empty() if you care that the value has an actual value that evaluates to not empty.
This blog entry implements The Beginner Pattern.
Brandon Savage is the author of Mastering Object Oriented PHP and Practical Design Patterns in PHP
Posted on 9/23/2009 at 1:00 am
Bruce Weirdan wrote at 9/23/2009 2:25 am:
Brandon, your description of isset() is far from true because you missed how it treats nulls. isset() returns false on a variable that has been set to null (but otherwise exist in the scope, does not throw notices on access, etc). I’m afraid the only sure way to test for variable existence in the scope is using array_key_exists + get_defined_vars()
And your last code snippet just doesn’t make sense, because strpos would never return null and you are assigning strpos result to $var, thus defining it. Taking out isset($var) check from there changes nothing – therefore it has no reason to be there in the first place.
BTW, both second and third snippets have emptyempty() instead of single empty(), and all of the examples have funky strings of amp;amp;amp;s
Daniel Andre Eikeland (@zegenie) wrote at 9/23/2009 3:49 am:
“If the variable has been defined in the global scope, in any form, this will return true. Otherwise, it will return false.”
Yes, this is the ideal way it works, but as Bruce mentions above, it simply isn’t true – and is a source of much unecessary headache.
Here’s the description from the documentation:
“Determine if a variable is set and is not NULL.”Also agree with Bruce that your examples aren’t very good.
Brandon Savage (@brandonsavage) wrote at 9/23/2009 5:49 am:
Bruce, I added a note about null; you’re right that it does create problems.
As for the amp;amp;amp; issue that’s due to the funky nature of my syntax highlighter. I resolved that. For some reason, I was unable to resolve the emptyempty issue, though; instead I replaced the examples with unhighlighted divs in the meantime.
I’m not sure what code examples would be better. I’ll think about it this morning and try to post something up later on in the day.
Daniel Andre Eikeland (@zegenie) wrote at 9/23/2009 5:52 am:
The point I usually bring up whenever a discussion about the odd isset() behaviour surfaces, is that PHP lacks a proper “variable_defined()” method – isset() tries to do both isset() *and* variable_defined(), which causes problems.
It’s really odd that there isn’t such a function, seeing as we already have defined() (for constants), and property_exists() (for class properties/class variables).
Brandon Savage (@brandonsavage) wrote at 9/23/2009 9:29 am:
I agree. I wanted to give beginners a method for using one or the other properly (this post is pretty fundamental), but I think you’re right that we need a variable_defined() function.
The PHP Internals list is waiting for your patch. ;-)
Richard Lynch (@LynchRichard) wrote at 9/23/2009 2:12 pm:
Please don’t use empty().
I can’t count the number of bugs and logic errors that I’ve run across over the years because of it.
Use isset() and then test the value with strlen() or == 0 or whatever is appropriate for the data type.
Plus, the actual definition of what is/isn’t empty changed with every major release so far. Not a very reliable function.
Cameron Junge wrote at 9/23/2009 6:43 pm:
A gotcha that not many people seem to either a) know about, or b) talk about is that a string containing 0 (ie. “0”) is also considered empty.
Eg:
$var = “0”;
echo (empty($var) ? ‘yes’ : ‘no’);Outputs: yes
Julian Egelstaff wrote at 9/23/2009 10:56 pm:
OK, maybe this will start a huge flame war reigning down on my head, but here’s another take on this…
If you’re an absolute beginner, one of the great things about PHP is that it really doesn’t care much about imperfect code. Just like HTML forgives all kinds of heresy, such as the case of properties in tags, and whether there are ” ” around values, and even whether there are proper closing tags or not on certain elements, PHP forgives lots of sloppy coding practices and still gives you a web page in your web browser despite what you’re doing “wrong”.
I think this is one of the most important features of PHP for beginners. It ramps up the feedback loop and makes the language really easy to tinker with and learn and teach, without having to get into more abstract programming issues like whether variables are set or null or something else.
If you think of it from the perspective of a non-programmer coming to PHP from HTML, these things that are bad coding practices to us, are what make PHP so accessible to them.
And these things have produced a lot of bad code. And given PHP a bad name in some circles. But that’s maybe a whole other story.
I do think that anyone who is serious about using the language needs to learn about these issues and incorporate them into their coding toolbox. But I think it’s wrong to declare that not using isset is wrong (and I’m not necessarily accusing the original post of saying that, just sensing it’s a perspective lying around here). If it were truly wrong, PHP would throw an error not a notice or warning or whatever it throws when you don’t do use it.
I think this idea is related a lot to the issues raised in “The Beginner Pattern” blog post at http://blog.phpdeveloper.org/?p=198. Introducing newcommers to the language takes a different perspective than the perspective that seasoned coders have, especially when a lot of newcommers to PHP do not have a coding background.
I am very interested to know what other people think of this, and especially how you would go about introducing this particular “isset” concept to a PHP newcommer. Should “bad habits” never be taught, or conversely at what point do you explain that the easy way you’ve been doing things up till now is actually not the best way to do things?
Maybe it’s not very insightful, but I would say that bad habits are just fine to start with, and the dividing line is when it starts to matter to the kind of things you’re doing with the code. The really hard part is how can a beginner identify that line? Maybe the most important lesson anyone can give to people starting with PHP is that they should simply be aware that there are many levels to climb before they master the language, and not to get set in their ways early.
–Julian
Logan Bailey wrote at 9/24/2009 2:47 am:
Nice article, another good article about this is:
http://www.phpro.org/articles/Difference-Between-isset-empty-is-null.htmlIt also contains the is_null() function as well.
Brandon Savage (@brandonsavage) wrote at 9/24/2009 7:51 am:
Juilian, I don’t usually allow flame wars…I think they’re bad for business. ;-)
I learned about notices when my web host turned notices on for code that was deployed on their servers. The practical use of eliminating notices for me was that they were scattered throughout my code – and that was bad.
PHP is very fault tolerant, and does a good job at mitigating a number of the issues that very junior programmers introduce. That said, I do think it’s wise to teach standards to new developers as much as is possible.
Is reducing or eliminating notices a critical component of writing PHP code? No. PHP code can work for years without eliminating notices. My goal in writing this article was two-fold: first, to identify a solution to a common problem, and second, to make new developers aware of the fact that things such as notices exist in PHP, hopefully prompting them to learn some more about it.
The next article in this series is a PDO primer. It discusses using PDO, and the flexibility that PDO provides. I didn’t want to spend time discussing the differences between =, == and ===, or really cover anything that’s explicitly talked about in the PHP manual; instead, I wanted to go a little deeper and expose new programmers to tools they might not have otherwise seen.
To that end, I’m pretty sure that this article was boring as hell for most advanced developers…at least, once I fixed it. ;-)
As for bad practices, they should *never* be taught. That’s just the way it is. Teaching bad practices results in bad practices, and I think that a gentle correction is appropriate. But we should never encourage bad behavior.
Steven Albarracin wrote at 10/1/2009 10:43 am:
I’ve actually used my own function which I believe addresses all the “empty/null/blank” values.
function checkIfNotSet($var,$zerosAreEmpty = false){
if($zerosAreEmpty) $empty = empty($var);
$var = trim($var);
if(!isset($var) || $empty ||$var == “”){
echo “Is Not Set”;
}else{
echo “Is set”;
}
}$var = 0;
checkIfNotSet($var);the trim function eliminates the use of the is_null function and also ” ”
Hope this will come in useful for someone out there.
Matthew Purdon (@mpurdon) wrote at 10/8/2009 12:17 am:
There are so many times when I wished that my fellow developers had developed with all errors being reported. You should always know what type your variables should be and use the appropriate test against them. Relying on a magic catch-all function not only allows ambiguity to creep in, it can prevent other developers from coding against your interfaces properly.
Dominik Bonsch wrote at 10/28/2009 11:28 am:
@Steven Albarracin you checkIfNotSet() has a bug ;-)
isset( $var ) in your function is not the same as using isset() in the code, cause of the parameter $var in your function $var always exists.
Maybe you should increase your error level for developing.
In my opionion there is no need for empty().
All you need ist isset() is_null() or trim($var) === ”.
This three methods are more specific than empty() and you get exactly the information you need, without any bug risk cause of 0 = false coversions etc..
« Why Interfaces Rock | Peer Review: You Have Not Because You Ask Not (Requests & Responses) » |