The Perils of the AT in PHP

July 27th, 2007 by Aaron

Save on Domains. Only $6.99 yr with 1&1

A lot of weird things have been happening ever since we introduced a new error handler at (”the triangle”). First of all, it took down our whole site for a good portion of time (oops!), then it created a large project for us to review our code. Turns out a lot of the errors were just weird little things that we ignored. However, there were a few times where the @ operator (http://us3.php.net/manual/en/language.operators.errorcontrol.php) was a huge problem. I, for once, don’t think that the @ operator should ever be used again. Let me detail out what it does and why I don’t think we should use it:

What does the @ do?

For most PHPers, they will answer with: “it supresses the error on that statement.” This isn’t entirely true. It actually internally changes the error_reporting() value at that one statement. Now, that one statement could also include many statements, if the statement is @require ‘myfile.php’… (all actions that happen as that file parses will have error reporting turned off).

Why is the @ harmful to performance

When I went to ZendCon 2006, I heard a talk about performance (I forget who it was now! :( ) - but they explained how the @ works. Basically, think of every time you execute a @’d statement, this is what happens internally:

1
@print 'hello';

is really something like…

1
2
3
4
5
$errorReporting = error_reporting();
error_reporting(0);
print 'hello';
error_reporting($errorReporting);
unset($errorReporting);

As you can see, even tho the internals of PHP are fast, thats a needless set of statements to call.

When does the @ not function as expected?

When you define a custom error handler, the @ doesn’t stop the error reporting. Instead, it sets error_reporting() to 0, but still executes the custom error handler. Of course, you can still facilitate the @ sign in your custom error handler by doing as so:

1
2
3
if (error_reporting() === 0) {
    return false;
}

What this does is exits the error handler right away (not so good - what if this was a fatal error?? - you’re now allowing the script to continue) and at least populates the $php_errmsg variable (return false allows this to happen).

How to not code with the @:

I can’t think of a legitimate, quality use for calling functions with the @. Notice I qualified that with ‘quality’. You can create code and use it to cut corners, but really, you’re just creating crappy code. Lets go over a few common usages of the @, and how you could code without using it again.

Require
Bad:

1
@require('myfile.php') or die('file was not included');

Better:

1
2
3
4
5
6
if (file_exists('myfile.php')) {
    require('myfile.php');
}
else {
    trigger_error('Could not include myfile.php', E_USER_ERROR);
}

Of course, make sure to read all about the caveats of file_exists.

Undeclared Variable Manipulation
Bad:

1
2
3
4
$value = @$myarray[0];
if ($value) {
    print 'do something';
}

Better:

1
2
3
4
5
6
7
$value = null;
if (isset($myarray[0])) {
    $value = $myarray[0];
}
if ($value) {
    print 'do something';
}

Tags: ,


3 Responses to “The Perils of the AT in PHP”

  1. Sean Says:

    Thanks for the article! I had a custom error-handler that was still spitting out errors that I thought I’d suppressed with “@” but were getting displayed anyway.

    As far as a “quality” reason to use the “@” sign, the only use I’ve found is functions like “mail” where you may not know ahead of time whether this function is supported on the server. I don’t think that there is an efficient way to check whether or not it is enabled (am I incorrect? that would be cool).

  2. aaron Says:

    I would check the function_exists as well as some of the php ini configs to see if your method exists. You might also check out here:
    http://us2.php.net/function_exists

    Check out the comments - so you can find out all kinds of useful information, like how to check the hardened PHP (suhosin) ini blacklist. Thanks!
    -aaron

  3. Sean Says:

    function_exists would actually show mail as working. It is defined, but the configuration is not done on it.

    It’s a REALLY weird case :-/

    I think we’re on the right path though… the thing that mail() complains about is the SMTP port not being set in php.ini… so we could just look up the four settings with ini_get like you mentioned and see if everything is there.

    For anyone who ends up here and is curious, the settings are here:
    http://us2.php.net/manual/en/ref.mail.php

    Thanks for a great article Aaron!

Leave a Reply

©2008 102 Degrees LLC - All Rights Reserved Home Services Products Network Blog Open Source Learning Contact