Feb 5, 2013

The "or else" ternary operator in PHP 5.3

Just wanted to share this quick tip about a tiny and frequently overlooked feature in PHP 5.3.

We've all had to write code like this in the past:

    public function get_events($day, $month, $year)
    {
        return (isset($this->events[(int)$year][(int)$month][(int)$day])) ?
                      $this->events[(int)$year][(int)$month][(int)$day]
                      : array();
    }


Repeating that whole array resolution is ugly, and probably error-prone, but it's no longer necessary since PHP 5.3:

    public function get_events($day, $month, $year)
    {
        return @$this->events[(int)$year][(int)$month][(int)$day] ?: array();
    }


Note the use of the error-suppression operator to prevent an E_NOTICE - there are very few legitimate uses for this operator, and this is one of them. Doesn't that look so much nicer? :-)

This variation of the ternary operator doesn't technically seem to have a name - it's considered a variation of the regular ternary operator used in the first example above.

Mnemonic tip: try reading the second return statement out loud, and read out the ?: operator as "or else".

Another example of how to put this operator to good use, is when a method might return a null-value:

    class Foo
    {
        public function __construct($value)
        {
            echo "Constructed an instance of Foo with value: $value\n";
        }
    }

    function getFoo($gimme)
    {
        return $gimme ? new Foo('default') : null;
    }

    // When getFoo() doesn't return an instance, create one:

    $test = getFoo(false) ?: new Foo('first');

    // When getFoo() does return an instance, don't create a second instance:

    $test = getFoo(true) ?: new Foo('second');


This will construct two objects: one with the value 'first' in statement (1) and another inside the call to getFoo in statement (2) - the object with the value 'second' will not be constructed.

This demonstrates a simple and elegant way to handle possible null-values, as opposed to using the long-hand ternary operator or if-else ladders. And the same is of course applicable in situations where a property might be null...