More concise ternary expression?

2019-04-29 00:25发布

I often find myself needing to write code with the following logical pattern:

$foo = isset($bar) ? $bar : $baz;

I know about the ?: syntax:

$foo = $bar ?: $baz;

...which, on the surface, appears to be what I'm looking for; however, it throws an undefined notice index when $bar is not set. It also uses the same logic as empty(), meaning that "empty" values like FALSE, 0, "0", etc. don't pass. Hence, it's not really equivalent.

Is there a shorter way of writing that code without throwing a notice when $bar is not set?

Edit:

To make it a bit more clear why I'm looking for a shortcut syntax, here's a better example:

$name = isset($employee->getName())
      ? $employee->getName()
      : '<unknown>';

In this case, $employee might be an object from a 3rd-party library, and it might be a valid scenario that its name might be NULL. I'd like to set variable $name to the returned name (if there is one), but some sensible default if there isn't.

If the method call is more complex than just a getter, then the example becomes even more verbose, since we have to cache the result:

$bar = $some->reallyExpensiveOperation();
$foo = isset($bar) ? $bar : $baz;

3条回答
Anthone
2楼-- · 2019-04-29 00:33

Using the error control operator you could technically shorten it to:

$foo = @$bar ?: $baz;

If $bar isn't set, the value evaluates to null, and you get no error notice since you suppressed the error. Some, however, might not approve of this code since its not nice to use @ since it masks errors and makes debugging more difficult.

Without that, no I don't believe there is a shorter notation that just using isset.

Edit: As noted by @drrcknlsn, this won't work if the variables are false, or 0, or even null, so it would seem to me that there is no avoiding the calling of isset.

查看更多
老娘就宠你
3楼-- · 2019-04-29 00:48

When $bar is not defined, there isn't really a "shorter" way to write the same code.

There are two, what I would consider "hacks" to do it, however, they also may impact other things:

  1. Error throttling with @, such as $foo = @$bar ?: $baz; will do exactly what you want and throttle the undefined-error that is thrown when $bar is undefined. If it is defined, it will also work as desired. The downside is, however, that @ can reduce efficiency in your code if it's used repeatedly.
  2. Turning off notices with error_reporting(E_ALL & ~E_NOTICE);. This will still display all regular errors but just not the notices, which will effectively hide the "variable is undefined" error. The downside to this is that you will not see any other notices.

Now, my obligatory personal opinion, I would suggest to continue writing it out full-hand. The ternary operator is already shorthand, effectively reducing the following:

if (isset($bar)) {
    $foo = $bar;
} else {
    $foo = $baz;
}

into a much shorter

$foo = isset($bar) ? $bar : $baz;

and it really doesn't take much more effort to write the full ternary versus the shorter-ternary (unless your variable names are ridiculously long, of course). Also, there are going to be more than a few instances where compound ternary operations (i.e. - several ternaries in one) that will cause the extra-shorthand to be unusable; so the short-savings is not programmatically/morally satisfying (in my own opinion).

UPDATE: To support your edit where you're assigning $bar to the return-value of a function and then $foo based off of it - you can combine the statements into a single-line like:

$foo = (($bar = $some->reallyExpensiveOperation()) != null) ? $bar : $baz;

This is almost the same code-length as the two lines, but it can be shortened slightly from here as well. For instance, if null isn't the only value that you consider "not valid", but false also counts, you can drop the != null portion entirely and allow the condition to be treated as a simple boolean value:

$foo = ($bar = $some->reallExpensiveOperation()) ? $bar : $baz;

In this example, $bar is still accessible after the ternary operation (i.e. - it doesn't lose scope), so unless you need to do pre-processing on the variable there isn't a big downside to this method, other than readability.

查看更多
可以哭但决不认输i
4楼-- · 2019-04-29 00:50

I would only use the short hand ternary syntax when you explicitly predefine your variables or use an object with a magic getter. This is a very basic example of where I would normally use short hand ternary syntax

class Foo {
    public function __get($name) {
        return isset($this->{$name}) ? $this->{$name} : '';
    }
}

$foo = new Foo();
$bar = $foo->baz ?: 'default';
查看更多
登录 后发表回答