Bad uses of the @ operator

In PHP, @ is called the error suppression operator. It is sometime a convenient way to tell PHP that it shouldn’t generate a warning (or a notice) at some piece of code because you know it’s perfectly correct to ignore that particular warning. I’ve found out that the @ operator, if overused, can impose an important speed penalty. Hense, here is a list of things you shouldn’t do with this operator.

Replacing isset

When you have a variable that you aren’t sure is set, do not use the error suppression operator to remove the “variable not set” notice, it’s about 2 times slower than using isset. Example:

if (isset($albus))  $albert = $albus;
else                $albert = NULL;

is equivalent to:

$albert = @$albus;

but while this second form is a nice syntax, it runs about two times slower. A better solution is to assign the variable by reference, which will not trigger any notice, like this:

$albert =& $albus;

However, using this assign-by-repherence trick may induce unintended side effects if you were going to modify any of the two variable later. My rule is to use this trick only in performance-critical areas and where I’m sure it won’t affect anything.

With the list construct

PHP allow you to assign multiple variables at once from an array using the list construct. The most common case of list is with the explode function which simply split a string in multiple parts. For example:

list($a, $b, $c) = explode('/', 'part1/part2/part3');

But often, you cannot be sure that the string you’re “exploding” has as many parts as you have variables listed. This will result in a PHP notice which is easily dismissed with the error suppression operator:

@list($a, $b, $c) = explode('/', 'part1/part2');

and in this case, the variable $c will be set to NULL. But again, @ is pretty slow. It’s so slow that, for this example at least, I’ve found that it’s faster to use array_pad to fill the array so that it contains enough values like this than to use the error suppression operator:

list($a, $b, $c) = array_pad(explode('/', 'part1/part2'), 4, NULL);

That’s getting pretty ridiculous.

The best solution I have found is to assign each variable by reference, like this:

$result = explode('/', 'part1/part2');
$a =& $result[0];
$b =& $result[1];
$c =& $result[2];

Since you weren’t going use $result anyway — you were using list which did not assign the full array to any variable — assignment by reference shouldn’t cause much trouble. From my testing, this is a little slower than using list, but still way faster than anything using the error suppression operator.

Conclusion

So what is to be remembered from all this? Simply don’t use the error suppression operator with speed-critical code. Writing more code to work around the tricky cases will always be faster.

Of course, if you don’t care about notices (most probably because you have set the error level to not include them) you don’t need any of these tips because you don’t need the error suppression operator for variable assignment. But if you’re deploying your software around on servers which do log notices, hopefully this information will be handy. At the very least, it will be for me and my PHP projects.


Notes: All tests were done with PHP 5 with error reporting at E_ALL. Results may vary with other versions and other settings.


Comments

flo

Could you please give us some details HOW you performed these tests? Thanks.

Michel Fortin

Yeah, sure. It’s pretty rudimentary:

$start_time = microtime(TRUE);

for ($i = 0; $i < 10000; $i++) {
    # -- Code to test here --
}

echo (microtime(TRUE) - $start_time);

(Written from memory.)


  • © 2003–2024 Michel Fortin.