It has been almost a year since PHP 7 was released into the wild. It gave us lots of great features, and because of some I often ask myself a question: "How could I possibly have lived without them?".

Scalar / Return type declarations

These two are probably the most recognizable PHP 7 innovations that allow us to write code this way:

public function isValid(string $email) : bool
{
    return filter_var($email, FILTER_VALIDATE_EMAIL);
}

By enforcing types of both method parameters and return value, your code becomes unambiguous, more strict, and therefore easier to debug. In order to make this really effective, don't forget to enable strict mode by putting declare(strict_types=1) directive in every file, so that type-checking runs for both your code and built-in PHP functions.

Another bonus is having a self-documented code. I hate docblock annotations on methods, but also comments in general, so by using these two gems my method signatures speak for themselves and I have autocompletion/hints in my IDE the natural way.

It should be noted that void return type will be available from PHP 7.1.

Null Coalesce Operator

Evaluating conditions using if/else statements is an essential part of programming, and ternary operator allows us to shorten and simplify our conditional logic. But for some cases it is limited, and shortened form actually looks cumbersome and bulky:

$username = isset($data['username']) ? $data['username'] : 'default';

PHP 7 solved this by granting us Null Coalesce operator:

$username = $data['username'] ?? 'default';

Joy does not end here because you can also chain coalescing:

$username = $data['username'] ?? $data['userName'] ?? $data['user_name'] ?? 'default';

Anonymous classes

I've already wrote about Anonymous classes, so here's a highlight from that post where I recognized their potential for writing test doubles:

public function testLoggerGetsInvokedWhenSet()
{
    $logger = new class implements LoggerInterface {
        public $log = [];

        public function log(string $message, array $context = [])
        {
            $this->log[] = [
                'message' => $message,
                'context' => $context,
            ];
        }
    };
    $this->service->setLogger($logger);

    $this->service->doSomething();

    $this->assertNotEmpty($logger->log);
}

Error Handling

There was one distinction of a PHP language that annoyed me the most and it was ambiguous error handling. By having that extra concept of fatal errors, making error handling consistent and uniform in our applications has always been an difficult undertaking.

In this regard, one of the most exciting changes in PHP 7 is converting fatal and catchable fatal errors into exceptions. This change comes with a whole new exception hierarchy:

\Throwable
├── \Exception (implements \Throwable)
│   ├── \LogicException (extends \Exception)
│   │   ├── \BadFunctionCallException (extends \LogicException)
│   │   │   └── \BadMethodCallException (extends \BadFunctionCallException)
│   │   ├── \DomainException (extends \LogicException)
│   │   ├── \InvalidArgumentException (extends \LogicException)
│   │   ├── \LengthException (extends \LogicException)
│   │   └── \OutOfRangeException (extends \LogicException)
│   └── \RuntimeException (extends \Exception)
│       ├── \OutOfBoundsException (extends \RuntimeException)
│       ├── \OverflowException (extends \RuntimeException)
│       ├── \RangeException (extends \RuntimeException)
│       ├── \UnderflowException (extends \RuntimeException)
│       └── \UnexpectedValueException (extends \RuntimeException)
└── \Error (implements \Throwable)
    ├── \AssertionError (extends \Error)
    ├── \ParseError (extends \Error)
└── \TypeError (extends \Error)

What this means is that now we can handle all the errors more gracefully, using try/catch blocks:

try {
    // Code that may throw an Exception or Error.
} catch (Throwable $t) {
}

Fin

This is only a small subset of awesome features that were introduced in the PHP 7, and those are one that I use the most.

Which PHP 7 features you use every day?