Suppressing suppressing PHP errors with emptiness
Posted on 28/1/09 by Felix Geisendörfer
PHP's language constructors that disguise as functions are a bitch! I didn't know that empty() does not throw errors when accessing non-existing array keys, but it's actually in the manual. Thanks to everybody who pointed it out!
So please consider my previous post garbage as far as the actual example is concerned. The proper solution is:
However, my threat of eventually using @ and breaking with other "best practices" remains. I will use whatever solution solves more problems for me then it creates ; ).
--Felix Geisendörfer aka the_undefined
You can skip to the end and add a comment.
If you go with the array_key_exists, I would suggest making a convenience function. You can even throw in the !empty().
if(ake('merge', $step['options']) ){
function ake($key, $ary) {
$is_there = array_key_exists($key, $ary);
return $is_there && !empty($ary[$key]);
}
@dooltaz
I think your function is a little redundant, since array_key_exists($key, $ary) && !empty($ary[$key]) is the same as only !empty($ary[$key]).
Remember that empty already check if the key exists on the array.
I think that empty is probably the best solution in this case. You have to be careful with empty() though, as it is can be a slippery function, if all you want to do is check the key's existence, then array_key_exists is the best tool, even isset() will return false if the key is set and === null. empty() is ideal when you want type coerce and swallow any possible errors.
I need to check if the key is true(ish) and dismiss all other scenarios. The key may be set to false in which case I don't care that it is set as all (ruling out array_key_exists).
So I'll stick with empty() : ).
Felix, the use of the @-operator is one of the biggest flaws in CakePHP. We should not spread this further, as this does NOT solve any problem at all!!
Explanation: If you run a serious production site (debug=0) you would not want to use setErrorReporting(0) in your application, since all errors are swallowed. You would depend entirely on the users reporting bugs (or go with bugs).
You would like to redirect you error messages into a file (See and fix: trac.cakephp.org/ticket/5660 *please, please, please, its only a few lines*)
If you are doing this, every error that is suppressed with the @-operator would get redirected into the error-file anyway, leading to confusion (See: trac.cakephp.org/ticket/3877)
Another point is performance. Suppressing an error, does not stop it from happening. Throwing the error and then suppressing it is unnecessary heavy-weight lifting for the PHP-Interpreter, which seriously affects performance, if done in a loop for example.
The list could go on
the_defined :): I can practically count on one hand the number of times the @ operator is used in Cake. Of those times, most of them are pretty inconsequential, i.e. console tools.
while ugly and verbose, for clarity and avoiding getting attached to a solution that only sometimes works (you may catch yourself doing this even when you care about more than truthiness). I have opted for the longer
if (array_key_exists('key', $array) && $array['key']))
which gives you pretty fine control and is still readable, still understandable, and simply adding a not operator to the second part of the conditional lets you work off false values instead.
my favourite feature of empty is its semantic readability :)
I feel like I'm missing something. In my php 5.2.6 trying to access an array index on an unset variable raises a notice. If the variable is set (type and value don't matter) no notice, warning or error is raised. Try it:
~$ php -a
Interactive shell
php > error_reporting(E_ALL);
php > echo $step['options']['merge'];
Notice: Undefined variable: step in php shell code on line 1
php > $step = 0;
php > echo $step['options']['merge'];
php >
Under what circumstances could this result in a warning? Have I completely missed your point?
@jcartledge if step is an array...
ohcibi@amsterdam:~$ php -a
Interactive shell
php > error_reporting(E_ALL);
php > $a = array();
php > echo $a['non']['existent']['index'];
Notice: Undefined index: non in php shell code on line 1
Call Stack:
17.6711 71180 1. {main}() php shell code:0
Dump $_SERVER
Dump $_GET
Dump $_POST
Dump $_COOKIE
Dump $_FILES
Dump $_ENV
Dump $_SESSION
Dump $_REQUEST
php >
empty() is best for your case
I found this and I thought it was wildly appropriate. Its from a Python article, part of a snippet called the Zen of Python, but I still think it's right :)
"Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced."
http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html
@ohcibi - thanks, it's a notice. All the discussion was of errors and/or warnings. I wouldn't generally expend this much effort silencing a notice, although the !empty() solution has the benefit of reading better than the original.
@Renan - Good point, but I'd rather not throw away the convenience function idea so quickly. One issue I run across quite often is I want to simply compare a value in an array to another value. For instance:
if (!empty($config['User']['username']) && $config['User']['username'] == 'admin') { ... Do Something ... }
This is a lot of typing. You could build an eq($config['User']['username'], 'admin') function that does the same comparison.
Just a thought.
I "solved" it by simply ignoring it in set_error_handler() callback function:
function my_error_handler(...)
{
if (strpos($message, 'Undefined index: ') === 0) return;
...
}
It worked for me for years and it has the plus of not only working for trueish checks.
This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.
why not using :
if(array_key_exists('merge', $step['options']) ){
which look more like what you were trying to achieve ie. checking the presence of the key "merge" ? though you might want to check its content in this case empty() alone is better use obviously.