We had a little bit of a discussion on twitter about the performance implications of errors in php.
I won’t surprise you as it is (should be) well-known that the error generation and the error suppression is slow. See this blogpost from Derick Rethans: http://derickrethans.nl/five-reasons-why-the-shutop-operator-should-be-avoided.html
So basically @$foo = bar; is slow because:
- an error will be generated and formatted regardless the error_reporting level or the existence of a custom error handler, because you can access the last error through error_get_last and $php_errormsg
- the @ operator only wraps the statement between two ini call: setting the error_reporting to 0, and restoring it to the original value. this is 2 more call to be executed and as you would guess, this means if you have a custom error handler, where you didn’t set the second $error_types parameter in your set_error_handler call, your custom error handler will be executed on the suppressed errors.
- as Derick pointed out, the Zend Engine will generate slower code to the suppressed statements.
I’ve just wrote a little benchmark on the issue, available on github
Basically it executes an assigment in a for loop, either using the string ‘foo’ or the non-existent constant foo, which will fallback to ‘foo’ and trigger a notice (I know, it is not a perfect test, because the constant lookup also has some overhead, but still better and more close to the real life issues than trigger_error()).
I mixed this with using the suppress operator and a custom error handler, here are the results:
- As you can see the overhead of having a custom error handler is almost negligible if it isn’t called.
- The suppression operator adds a small overhead without errors. (~1.6X)
- Having an error without @ or custom error handler still slow (~5.7X).
- if you have an error and a custom error handler which gets executed, that yields for a ~10X performance loss, regardless of using the suppression operator or not.
So my advices:
- if you see errors in your log, fix them, thats also a performance gain.
- if you use custom error handler, don’t forget to set the $error_types, you can use bitmask like for error_reporting(in our case E_ALL &~ E_NOTICE), or you can pass the error_reporting() to set your handler to the same level as your error_reporting.
- don’t overuse the @ operator, and if you do, always handle the return values of your suppressed statements, or you will suck big time when you have to debug your application (check out the scream pecl extension or xdebug.scream)