开发者

PHP: Best Practices for Silent Failure

I find myself doing this a lot:

$something = @$_GET['else'];
if ($something) {
    // ...
} else {
    // ...
}

Like, almost whenever I deal with arrays. I'm used to JavaScript and the ability to simply check for a falsy value. But is this appropriate in PHP? Am I trying to force PHP to be something I already understand, instead of learning it as its own language?

EDIT

I udnerstand that I can just use isset (I also *under*stand it), but it feels clunky to me, and it leads to even clunkier situations where I'm trying to echo the value:

// what I want to do
echo '<input type="text" name="whatever" value="', @$values['wha开发者_如何学Ctever'], '" />';

// what I fear I must do
echo '<input type="text" name="whatever" value="';
if (isset($values['whatever'])) {
    echo $values['whatever'];
}
echo '" />';

Setting aside the sanitation issue, I prefer the first version. But I have a sneaking suspiscion that it's a big no-no. (I also have a sneaking suspicion that I don't know how to spell "suspicion.")


I recommend NEVER using the @ operator. It encourages bad code and can make your life miserable when something doesn't work and you're trying to debug it.

You can of course disable notices in php.ini, but if I were you I would start using isset() more :)

You can do something like this:

echo '<input type="text" name="whatever" value="', (isset($values['whatever'])?$values['whatever']:''), '" />';

You can read more about how horrible @ is, here: http://php.net/manual/en/language.operators.errorcontrol.php

Well, it's the actual error triggering that is expensive. Using @ triggers the error. Checking with isset() instead, does not. http://seanmonstar.com/post/909029460/php-error-suppression-performance


To answer the title: Best way is to turn off display_errors.

For what you're doing specifically, use isset().

Note: To those complaining that this 'turns off' all errors -- from the PHP manual:

This is a feature to support your development and should never be used on production systems (e.g. systems connected to the internet).

After the Edit: You could either make sure the variables you're going to use have some value (just blindly echoing a get/post var isn't the best practice) - or you could use an object to store the variables you want to output (as properties) and use __get() to return an empty string (or a false) when the property hasn't been set.

That would leave you with something like:

echo $view->something;
if($view->something){
   //stuff to do when something is set
}

I believe that would be similar to what a lot of template/view libraries do.

Update: Noticed this old(ish) answer, and thought something could be added to it. For this use case (where values may or may not be in an array), array_merge() could be used:

$default = array('user' => false);
$params = array_merge($default, $_GET);
if($params['user']){ //safe to use, will have default value if not in $_GET

}


Why you want to surpress something, that will not occur, if you check the array before accessing it?

$something = array_key_exists('else', $_GET) ? $_GET['else'] : null;
$something = isset($_GET['else']) ? $_GET['else'] : null;

Your way seems to be just the solution for the lazy ones.

However, the @-operator is never a good idea as long as you can avoid it (and there are really very less situation, where you cant avoid it). Its also quite inperformant.


Use a general function for array accesses:

/**
 * Function for accessing array elements and returning a
 * default value if the element is not set or null.
 * @param string $key Name of index
 * @param array $array Reference to an array
 * @param string $default Value to return if the key is not
 *        found in the array
 * @return mixed Value of array element (if it exists) or whatever
 *        is passed for default.
 */
function element( $key, &$a, $default = '' )
{
    if( array_key_exists( $key, $a ) && !is_null( $a[$k] ) )
    {
        return $a[$key];
    }
    return $default;
}

Then your HTML output can look like this:

echo '<input type="text" name="whatever" value="'
   , element( 'whatever', $values ), '" />'
;


I've said it before and am happy to say it again:

$else = isset($_GET['else']) ? $_GET['else'] : null;

Is equivalent to:

$else = @$_GET["else"];

The difference is that one is less readable due to syntactic salt for error suppression, and the other uses the intended language feature for that. Also notice how in the second case the notice (many people don't comprehend the difference to errors) can still be uncovered by custom handlers.

For all practical purposes you should use neither. Use simply:

$else = $_GET["else"];

Turn off debug notices while you don't need them.

(Practically I'm also usually using the dumb isset() method. But I'm using object-oriented superglobals, rather than PHP4-style $_POST and $_GET arrays, so it's just one hidden isset() and doesn't pollute my code.)


This is a common problem and while the solution is simple, you're right that it's not pretty. Personally I like to use wrappers. You can very easily write a simple class that implements ArrayAccess by wrapping the array passed in. It would do the key check internally (in one place), and quietly return null when asked for a non-existent key. The result looks something like this:

'bar')); var_dump($arr['foo']); var_dump($arr['zing']); // string(3) "bar" // NULL ?>

This may also feel more familiar to you, coming from Javascript, as you can add new functionality to the class as well, like custom sorting, or maybe filtering.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜