debuggable

 
Contact Us
 

Suppressing PHP errors for fun and profit

Posted on 28/1/09 by Felix Geisendörfer

Update: The conclusions below are wrong, empty() is the best solution to the particular problem, read the follow up post for more information.

As of late I am getting sick of some best practices I have taught myself. Never using the @-error suppressing operator quickly moving to the top of the list.

Before you start crying out loud (I know you will), let me say this: I do not mean to encourage anybody to use the @-operator. Applying the practice herein introduced may result in permanent damage to your coding habits and could serve as a gateway behavior to writing shitty code.

Ok, you have been warned, lets move on. Today I found myself writing the following line of code:

if (isset($step['options']['merge']) && $step['options']['merge']) {
  // do stuff
}

I was basically checking for a sub-key of an element to be true(ish). However, I knew this sub-key may not be included in the array under some circumstances, so a direct check for it could result in a PHP warning.

You can probably feel the pain of conflict here. On one side I want to write very short and expressive code. On the other side I am also trying to follow the so called "best practices". It is impossible.

Of course there is always the option to normalize the array before doing the check:

$step['options'] = array('merge' => false) + $step['options'];
if ($step['options']['merge']) {
  // do stuff
}

This however still adds a basically useless line of code. Plus normalizing a multi-dimensional array like this requires a more sophisticated merging algorithm than PHP provides you with (CakePHP's Set::merge() function provides good multi-dimensional array merging, but that would be throwing even more code and CPU cycles at the problem).

So today I have, for probably first time in years, I wrote the following line of code:

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

It still causes me mild pain to look at. I hope for that to go away soon. But I no longer have the strength to close my eyes to the very true lesson to be learned here: Using the @-operator like this solves more problems for me than it creates.

This may not be true for you. Using the @-operator is 4x slower than solution #1 and 1.3x slower than #2. If you run a loop with 100000 records, this is 150ms wasted (on my laptop, your mileage may vary). However, my scenario is more like running into this 5-10 times for any given request. So we are talking about 0.0015ms here.

It is not like I don't care about my CPU-cycle footprint. The opposite is true. By sparing myself the pain of typing up and maintaing more verbose-than-necessary code I can save millions of CPU cycles elsewhere! I can go and optimize stuff that actually needs to be optimized.

How will you choose?

-- Felix Geisendörfer aka the_undefined

PS: In case you wonder, @-suppressed errors do not show up in any error logs. So no problems with that.

 
&nsbp;

You can skip to the end and add a comment.

Mladen Mihajlovic  said on Jan 28, 2009:

How about?

if (isset($step['options']) && isset($step['options']['merge']) && $step['options']['merge']) {
// do stuff

}

Christof said on Jan 28, 2009:

How about:

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

}

Usage of '@' is horrible. It might look okay in this simple case, but a few weeks later you change the code to something like this:

if (@$step['options']['merge'] && really_check_for_merge($step)) {
// do stuff

}

and you will never find a bug in the expression.

Luke  said on Jan 28, 2009:

use if !empty() no? As it doesnt throw an error if it is not there, but will still tell you if you havea true

Sam said on Jan 28, 2009:

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

}

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.