3

So I'm working on cleanup of a horrible codebase, and I'm slowly moving to full error reporting.

It's an arduous process, with hundreds of notices along the lines of:

Notice: Undefined index: incoming in /path/to/code/somescript.php on line 18

due to uses of variables assuming undefined variables will just process as false, like:

if($_SESSION['incoming']){
    // do something
}

The goal is to be able to know when a incorrectly undefined variable introduced, the ability to use strict error/notice checking, as the first stage in a refactoring process that -will- eventually include rewriting of the spots of code that rely on standard input arrays in this way. There are two ways that I know of to replace a variable that may or may not be defined in a way that suppresses notices if it isn't yet defined.

It is rather clean to just replace instances of a variable like $_REQUEST['incoming'] that are only looking for truthy values with

@$_REQUEST['incoming'].

It is quite dirty to replace instances of a variable like $_REQUEST['incoming'] with the "standard" test, which is

(isset($_REQUEST['incoming'])? $_REQUEST['incoming'] : null)

And you're adding a ternary/inline if, which is problematic because you can actually nest parens differently in complex code and totaly change the behavior.

So.... ...is there any unacceptable aspect to use of the @ error suppression symbol compared to using (isset($something)? $something : null) ?

Edit: To be as clear as possible, I'm not comparing "rewriting the code to be good" to "@", that's a stage later in this process due to the added complexity of real refactoring. I'm only comparing the two ways (there may be others) that I know of to replace $undefined_variable with a non-notice-throwing version, for now.

Kzqai
  • 22,588
  • 25
  • 105
  • 137
  • Possible duplicate: http://stackoverflow.com/questions/136899/suppress-error-with-operator-in-php (see also the most upvoted answer there) – igorw Sep 26 '11 at 17:58

7 Answers7

5

Another option, which seems to work well with lame code that uses "superglobals" all over the place, is to wrap the globals in dedicated array objects, with more or less sensible [] behaviour:

class _myArray implements ArrayAccess, Countable, IteratorAggregate
{
     function __construct($a) {
       $this->a = $a;
     }

    // do your SPL homework here: offsetExists, offsetSet etc

    function offsetGet($k) { 
        return isset($this->a[$k]) ? $this->a[$k] : null;
        // and maybe log it or whatever
    }
}

and then

 $_REQUEST = new _myArray($_REQUEST);

This way you get back control over "$REQUEST" and friends, and can watch how the rest of code uses them.

user187291
  • 53,363
  • 19
  • 95
  • 127
  • This is something that I hadn't really though of, and is a pretty clever way for me to get the refactoring started, and as you say, take control. – Kzqai Sep 26 '11 at 17:41
  • Very nice solution, in the `offsetGet` method I added a check for the value being an array, so instead of the original array it would return an "extended" array. This should work for checking also nested arrays like `$_REQUEST['a']['b']` – Minkiele Sep 26 '11 at 21:43
2

You need to decide on your own if you rate the @ usage acceptable or not. This is hard to rate from a third party, as one needs to know the code for that.

However, it already looks like that you don't want any error suppression to have the code more accessible for you as the programmer who needs to work with it.

You can create a specification of it in the re-factoring of the code-base you're referring to and then apply it to the code-base.

It's your decision, use the language as a tool.

You can disable the error suppression operator as well by using an own callback function for errors and warnings or by using the scream extension or via xdebug's xdebug.scream setting.

hakre
  • 193,403
  • 52
  • 435
  • 836
1

You answered you question yourself. It suppress error, does not debug it.

Starx
  • 77,474
  • 47
  • 185
  • 261
  • This doesn't mean anything to me. I've clarified my question to make exactly the comparison I'm making more clear, but in using either isset and @, I have only the first goal in mind of getting the overall codebase to a state of being able to see newly introduced variables that aren't properly defined. Neither is being used to "refactor" bad code to good code at this point, so neither is being used to "debug" the code. – Kzqai Sep 26 '11 at 17:29
  • Ok, then I will answer it on your term. An essential reason to use isset over @ in PHP is to remove the an error from a statement where as for its counter part who only suppress(hides) the error so that the program execution will continue flawlessly. – Starx Sep 26 '11 at 17:34
1

In my opinion you should be using the isset() method to check your variables properly.

Suppressing the error does not make it go away, it just stops it from being displayed because it essentially says "set error_reporting(0) for this line", and if I remember correctly it would be slower than checking isset() too.

And if you don't like the ternary operator then you should use the full if else statement. It might make your code longer but it is more readable.

Lucas
  • 10,476
  • 7
  • 39
  • 40
  • that is interesting, maybe I'll look into the actual source behavior that @ is engaging in. – Kzqai Sep 26 '11 at 17:24
  • Just fyi, it doesn't work at the line level per se, as this code: `$bob = @$_REQUEST['something'];` `$bob = (@$_REQUEST['something'] || $_REQUEST['somethingelse']);` Still throws a notice on the final uninitialized variable. – Kzqai Sep 26 '11 at 17:47
1

I would never suppress errors on a development server, but I would naturally suppress errors on a live server. If you're developing on a live server, well, you shouldn't. That means to me that the @ symbol is always unacceptable. There is no reason to suppress an error in development. You should see all errors including notices.

@ also slows things down a bit, but I'm not sure if isset() is faster or slower.

If it is a pain to you to write isset() so many times, I'd just write a function like

function request($arg, $default = null) {
   return isset($_REQUEST[$arg]) ? trim($_REQUEST[$arg]) : $default;
}

And just use request('var') instead.

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • most misleading answer ever. "I would naturally suppress errors on a live server", my foot! How do you think what error massages are for? To annoy a programmer? – Your Common Sense Sep 26 '11 at 17:19
  • 1
    @Col.Shrapnel you really want your users to see "Notice: Undefined Index blah on line 46?" – Explosion Pills Sep 26 '11 at 17:20
  • I do, actually, have a function called in() to handle $_REQUEST for exactly this reason, so perhaps $_REQUEST isn't the best example for my specific case. The horror is that most of the other situations where it's in use are with $_SESSION. Everywhere. Anywhere values are meant to be used cross-page. It's quite the abuse of php this code. – Kzqai Sep 26 '11 at 17:27
  • No, I am not. But I have to see any error occurred myself, to take an appropriate action. So, suppressing error messages is NOT the way to go. If you don't want error messages to be displayed to user, make them not displayed but don't suppress them. Easy, eh? – Your Common Sense Sep 26 '11 at 17:32
  • `ini_set('display_errors', false)` could be considered error suppression and that's probably what the answerer was referring to. – webbiedave Sep 26 '11 at 17:36
  • @Col.Shrapnel, is not totally incorrect. Errors, whether notice or fatal errors, they have a genuine purpose of being there and alerting itself, so that programmers who actually care about efficient coding can benefit from it. – Starx Sep 26 '11 at 17:37
  • @Col.Shrapnel, ha ha, I was just referring to you, not replying to you, although it seems like that. Sorry for that :) – Starx Sep 26 '11 at 18:03
  • @Col.Shrapnel I mean what webbiedave suggests, but that is only on the live server. On the development server, all errors should be displayed at all times. Where is the disconnect for you here? – Explosion Pills Sep 26 '11 at 19:08
  • @Tchalvak you could create a similar function for `_SESSION` – Explosion Pills Sep 26 '11 at 19:09
  • @tandu Right, and the only reason I haven't done that yet is because the (horrible) session is a mix of stored-for-user variables and secure authentication variables. As a result of this discussion I've decided to split it into two things: A function to store secure authentication variables (user id, username.... ...that's probably about it). And one to store variables/settings just for re-use, for which I'll just use the database, like should have been done in the first place. Either that or something using stereofrog's slick suggestion somehow. – Kzqai Sep 26 '11 at 19:54
0

I've actually discovered another caveat of the @ beyond the ones mentioned here that I'll have to consider, which is that when dealing with functions, or object method calls, the @ could prevent an error even through the error kills the script, as per here:

http://us3.php.net/manual/en/language.operators.errorcontrol.php

Which is a pretty powerful argument of a thing to avoid in the rare situation where an attempt to suppress a variable notice suppressed a function undefined error instead (and perhaps that potential to spill over into more serious errors is another unvoiced reason that people dislike @?).

Kzqai
  • 22,588
  • 25
  • 105
  • 137
0

Most so-called "PHP programmers" do not understand the whole idea of assigning variables at all.
Just because of lack of any programming education or background.

Well, it isn't going a big deal with usual php script, coded with considerable efforts and consists of some HTML/Mysql spaghetti and very few variables.

Another matter is somewhat bigger code, when writing going to be relatively easy but debugging turns up a nightmare. And you are learn to value EVERY bloody error message as you come to understanding that error messages are your FRIENDS, not some irritating and disturbing things, which better to be gagged off.

So, upon this understanding you're learn to leave no intentional errors in your code.
And define all your variables as well.
And thus make error messages your friends, telling you that something gone wrong, lelping to hunt down some hard-spotting error which caused by uninitialized variable.

Another funny consequence of lack of education is that 9 out of 10 "PHP programmers" cannot distinguish error suppression from turning displaying errors off and use former in place of latter.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • Ufff, I can happily say I have dodged all those boulders. hehe – Starx Sep 26 '11 at 18:06
  • This is true, and in a perfect world you'd never have to "downgrade" your practices once you learned the better approaches, but when you're dealing with someone else's horrible code, and trying to clean it up, that's when you need to find a pragmatic approach. Certainly I love a clean codebase where I can use E_ALL | E_STRICT without compromise. I am not working on such a nice thing. Simply switching to higher error reporting makes an unreadable mess with the high volume of notices. :p – Kzqai Sep 26 '11 at 19:49