debuggable

 
Contact Us
 

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:

if (!empty($step['options']['merge'])) {
  // do stuff
}

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

 
&nsbp;

You can skip to the end and add a comment.

zerterone  said on Jan 28, 2009:

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.

dooltaz said on Jan 28, 2009:

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]);

}

Renan Gonçalves (aka renan.saddam) said on Jan 28, 2009:

@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.

Mark Story said on Jan 28, 2009:

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.

Felix Geisendörfer said on Jan 28, 2009:

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() : ).

the_defined :)  said on Jan 28, 2009:

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

Nate Abele said on Jan 28, 2009:

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.

ruzz said on Jan 28, 2009:

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.

Luke aka boobyW  said on Jan 29, 2009:

my favourite feature of empty is its semantic readability :)

jcartledge  said on Jan 29, 2009:

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?

ohcibi said on Jan 30, 2009:

@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 >

Rob  said on Jan 30, 2009:

empty() is best for your case

ruzz said on Jan 31, 2009:

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

jcartledge  said on Feb 01, 2009:

@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.

dooltaz said on Feb 03, 2009:

@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.

Francesc Rosàs said on Mar 13, 2009:

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.