45 comments

[ 3.4 ms ] story [ 86.7 ms ] thread
One reason to use it: to silence functions that generate warnings when the falsy return value would suffice.

http://php.net/manual/en/function.parse-url.php

5.3.3 Removed the E_WARNING that was emitted when URL parsing failed.

A logical first step would be to fix all of those functions in PHP that end up requiring the use of @. Once that is done then we could move forward with removing all @ use.
Another one that I ran into at the same time as parse_url is that passing NULL to urldecode would throw a notice, which was simpler to @ away then check first since it always returned an empty string anyway.
According to the changelog for parse_url that is no longer the case for 5.3.3 and up.
Whenever the @-operator is used, PHP needs to invoke the INI settings mechanism to change the temporary value of the error_reporting setting to 0.

Can't make this stuff up.

That's not too bad assuming that only that thread is affected.

I can't think of another way to do it that wouldn't effectively reduce to this anyway.

PHP doesn't use threads unless you are using the pthreads extension [1]. I am not sure how it would affect that ext. Normally it won't affect any other PHP scripts that are running.

[1] https://github.com/krakjoe/pthreads

Oh, it's just one of thousands of nonsensical PHP features.

Like the fact that the language's grammar is used to do primitive type checking, meaning some combinations of accessors cause errors.

Or the fact the mail sending function doesn't work if one of the lines in the email begins with a period, but only if you're on Windows.

Some of the weirder OS-specific function behaviors can be a rationalized a little better if you view PHP functions not as sane, complete library functions, but rather as thin wrappers to the underlying OS. For mail() it basically just wraps the system's mail program in Linux (which comes with a huge number of dangerous gotchas for the uninitiated) and I imagine in Windows it wraps the local mail program which seems to have a gotcha with periods. I think a lot of the file management functions are the same.

That's one of the many problems with PHP's underlying design philosopy: instead of providing a higher-level interface that stays consistent across platforms, it exposes low-level OS gunk and gotchas through its thin wrappers on low-level-ish functions. I put together phpbestpractices.org a few months ago in an attempt to document some of those common gotchas and provide sane alternatives.

>PHP functions not as sane, complete library functions, but rather as thin wrappers to the underlying OS.

Except they're not really that thin.

>in Windows it wraps the local mail program which seems to have a gotcha with periods

Nope, in Windows it implements the SMTP protocol, on UNIX it runs sendmail.

>instead of providing a higher-level interface that stays consistent across platforms, it exposes low-level OS gunk and gotchas through its thin wrappers on low-level-ish functions.

Except it doesn't. There's quite a few things that are named like OS functions, but are implemented internally. For example, all the C stdlib-like string functions.

My mistake then :) I admit I haven't read the source, I'm just going off of the quirkiness of cross-platform PHP and the way the functions seem to behave.
It doesn't actually change the INI file. It changes the error_reporting setting in memory while that one function is executing and when it finishes it changes it back.
It still is a weird unexpected side effect and at least a hash lookup in a map
I don't see how this is a 'side effect'. It accomplishes the exact task it is designed to and doesn't do any quirky, or 'side', behavior to the script.

Also, I wouldn't be worried about one lookup. I'm pretty sure everything in PHP is in a hash map.

No, it's actually a good idea. That way I can programmatically check if any error is going to be reported inside of a method or function that's being silenced. And, on top of that, override the silencing within a method or function directly. Using an established interface provides me with a ton of options ... options I wouldn't have if it did some sort of internal voodoo.
But you then can never know what the actual real ini value is. The override should be a different interpreter state variable (if at all).
One reason you might actually want to silence a warning.

You might be developing an application that functions in some P2P type fashion or is specifically intended to be used in situations where network access will be intermittent (on a boat perhaps?).

In such a case a mysql_connect call may have a high chance of failing and your application is designed in such a way as to assume that this is likely (i.e working with the return code). In such a case failing the connection is not an error but expected behaviour.

Problem is when you suppress the error to handle failed connections but didn't anticipate other errors which go unnoticed and make tracking bugs VERY difficult.
This flags a design flaw, perhaps in mysql_connect. If a warning is trivial enough that it's reasonable to silence, it shouldn't exist. Otherwise, it's not reasonable to silence it!

I find it hard to believe that this is actually considered acceptable.

Surely that depends on your application, in 99.9% of cases where you are using LAMP to host some site a failed mysql_connect is probably an epic fail condition.

My point is rather that there may certainly be applications where this is not the case.

This is an area where exceptions are better than dumb warnings.

Don't use mysql_*. Says so right in the docs. PDO can be used with try/catch.
Using mysql_query is an epic fail condition. Period.
The guys at Smarty did some pretty good analysis on the @ operator - specifically in cases where implementing it improved performance: http://blog.rodneyrehm.de/archives/12-Improving-Disk-IO-in-P...
Well it comes down to deciding on avoiding race conditions vs bad opcode generation, I guess.

Maybe the solution is to use php 5.4 if it makes better silence code but I am having a hard time letting go of suhosin.

Yeah ... not having SuHoSin for PHP 5.4 means I haven't deployed it yet. I want to upgrade, but I like the extra security SuHoSin gives me.
I fear it's never coming for 5.4, Stefan Esser seems to have moved onto ios security.
@operator is much faster in 5.4.x

$x = @$f["x"] is right place to use it.

$x = @custom_func() - is a disaster, do not do it

> $x = @$f["x"] is right place to use it.

No, it's not. There's built-in methods for that: isset() and empty().

Or array_key_exists(), depending on exactly what you're hoping for :(
empty() is not a good idea. What if $f["x"] is an empty string ""? Or 0, or 0.0, or "0", or any of the other values for which it returns true?
It completely depends on the use case. My point was, don't use @
so what is wrong with;

if(function_exists(custom_func) { $x = @custom_func(); }

if((!isset($x)) || (empty($x))) { echo('Custom Error'); } else { //Do the work }

This may be considered verbose, but can be useful if custom or "sometimes" installed libraries are involved

> if(function_exists(custom_func) { $x = @custom_func(); }

http://php.net/manual/en/function.call-user-func.php

Why would you prepend @ to your function call?

> if((!isset($x)) || (empty($x))) { echo('Custom Error'); } else { //Do the work }

You're duplicating your efforts. empty() takes into account if a variable or key has been initialized, and also if it has a non-false value. isset() only checks if the variable/key has been intialized and nothing else.

It's interesting to find out just how many ways @ is bad but this article is going to fall on deaf ears. The people that can be convinced that it's bad are already not using it. Those that need to be told why the "ignore broken things and keep on trucking" operator is bad, aren't paying attention anyways.
There are cases where you want something silenced. In my code base, there is one place where it is used and I need it there.

I frequently use file_get_contents to retrieve data stored on external servers. If there is a network error or the external service goes down temporarily, it will trigger an error. I don't want my log files flooded with transient error messages that are outside of my control. Instead, I just want it to try again. @ makes this possible.

We opt to use the curl functions for that.
I understand that decision, but I actively try to remove any extensions that I can do without to keep the PHP binary slim and even more reliable. My personal way of doing things, that's all. file_get_contents can do everything the curl extensions can, provided that you use the context options, so I just use that and remove curl when I compile the PHP binary.
There is a reason scream exists in xdebug. There is a reason it's called scream.
Reason 6: its part of PHP.
Some negative comments about the @-operator seem to be very religious. It's just a tool that one can use for good or for evil. Many of the reasons not to use @ described are valid, but there are cases when it makes much cleaner code. E.g. instead of doing: if (array_key_exists($key, $a) && $a[$key] == $value) dostuff(); you can do: if (@$a[$key] == $value) dostuff(); This works really well when you don't care whether $a[$key]is present or not, and when you care only whether it contains a certain $value. In complex comparisons the code readability difference is huge!