Chapter 4. Basic Language Changes

PHP 7.0 introduces numerous small changes to the language, new operators, functions, and changes to existing functions and constructs.

Operators

PHP 7.0 adds two new operators, the null coalesce operator and the combined comparison operator.

Null Coalesce Operator

The new null coalesce operator ?? will return the left operand if it is not null; otherwise, it returns the right operand. The most interesting part of this operator is that it will not emit a notice if the operand is a nonexistent variable—similar to isset().

Effectively, this is a shortcut for isset() combined with a ternary for assignment. Example 4-1 shows this new, more compact syntax compared to the older syntax.

Example 4-1. Null coalesce operator
$foo = isset($bar) ? $bar : $baz;

$foo = $bar ?? $baz;

The two lines in the preceding example are functionally identical.

You can also nest the operator, and it will return the first non-null (or the last argument), as shown in Example 4-2.

Example 4-2. Nested null coalesce operators
$config =   $config ??
            $this->config ??
            static::$defaultConfig; 1
1

This shows a common fall-through scenario, whereby a local configuration may be set in $config, otherwise fallback to the instance level $this->config, or finally, fall back to the static defaults static::$defaultConfig.

Combined Comparison Operator

Affectionately called the spaceship operator, the combined comparison operator (<=>) is the first trinary operator in PHP.

This means that rather than return a simple binary true or false, it can actually return three distinct values:

  • -1 if the left operand is less than the right operand

  • 0 if the operands are equal

  • +1 if the left operand is greater than the right operand

This is frequently used for sorting items, for example, using the usort() function with a callback.

The following two functions are identical, the first using PHP 5.x syntax, and the second using the new combined comparison operator. You can compare the older, less compact syntax in Example 4-3.

Example 4-3. Sorting with the combined comparison operator
// Pre Spacefaring^W PHP 7
function order_func_traditional($a, $b) {
    return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
}

// Post PHP 7
function order_func_spaceship($a, $b) {
    return $a <=> $b;
}

Constant Arrays

Up until now, constants defined with define() could only contain scalar values. With PHP 7.0, they have been updated to match constants defined by const, allowing you to set them to constant arrays. Example 4-4 demonstrates this new capability.

Example 4-4. Constant arrays using define()
define('FOO', [
    'bar' => 'baz',
    'bat' => 'qux'
]);

echo FOO['bar']; 1
1

This will output baz.

Unpacking Objects Using list()

The list construct will now allow you to unpack objects that implement the \ArrayAccess interface, allowing you to use them just like arrays, as shown in Example 4-5.

Example 4-5. Unpacking objects using list()
$object = new \ArrayObject(json_decode($json)); 1
list($foo, $bar, $baz) = $object;
1

\ArrayObject implements \ArrayAccess and can take an array, or an object, so no matter which json_decode() returns, we can now use it with list().

New Functions

Several new functions have been added with this release.

Integer Division

The new intdiv() performs integer division, effectively the inverse of the modulo operator (%). Example 4-6 shows an example of this new function.

Example 4-6. Integer division
intdiv(8, 3); 1
1

Returns two.

Regular Expressions

As shown in Chapter 2, ext/ereg has been removed, but this isn’t the only change to regular expressions in PHP 7.0.

This release adds a new preg_replace_callback_array() function that makes it much nicer to perform a number of regular expression replacements with different callbacks for each. As shown in Example 4-7, you pass in an array with regular expressions for keys, and closures—or other callables—that accept an array of matches. All matches will be replaced with the return value from the callable.

Example 4-7. Multiple replace callbacks
$header = "X-Custom-Header: foo\nbar";

$normalizedHeader = preg_replace_callback_array(
    [
        "/(.*?):/" => function($matches) {
            return strtolower($matches[0]);
        },
        "/\s+/" => function($matches) {
            return "-";
        }
    ],
    $header
); 1
1

This will transform the input header to x-custom-header:-foo-bar.

The other change to the PCRE functions is the removal of the /e modifier used with preg_replace(). This modifier allowed you to use code that would be evaluated against matches to create the replacement value. You should use preg_replace_callback() or the new preg_replace_callback_array() instead.

Cryptographically Secure Values

Traditionally, we’ve resorted to either very poor sources of randomness or openssl to generate cryptographically secure integers or strings.

PHP 7.0 adds two new simple functions, random_bytes() and random_int() to solve this problem in a platform-independent way.

CSPRNG functions

Collectively, these form the CSPRNG functions. CSPRNG stands for cryptographically secure psuedorandom number generator.

As you might expect from the name, random_int() will return a random integer from a range, while random_bytes() will return a random string of a given length as shown in Example 4-8.

Example 4-8. Generating cryptographically secure random values
random_bytes(16); 1
random_int(0, 10000); 2
1

Returns 16 random bytes in binary format. You will probably want to pass the result to bin2hex() before using it.

2

Returns a random number between 0 and 10000.

Function Changes

There have also been a few changes to existing functions.

Sessions

It is now possible to pass an array of INI settings to session_start().

A new setting session.lazy_write has also been added. This new setting, which is enabled by default, will mean that session data is only rewritten if there has been a change to it.

You can disable this new setting as shown in Example 4-9.

Example 4-9. Changing session configuration on call
session_start([
    'use_strict' => true,
    'lazy_write' => false
]);

Filtered unserialize()

In an attempt to enhance security, it is now possible to filter which classes will be instantiated when unserializing using unserialize().

This is done by adding a second argument that takes an array of options, of which there is currently only one, allowed_classes.

You can pass in one of three values for the allowed_classes option:

  • false will instantiate all objects as __PHP_Incomplete_Class object instead.

  • An array of class names will instantiate those as-is and return __PHP_Incomplete_Class for any others.

  • true will result in the same behavior we’ve always had, and all objects will be instantiated they are.

Move Up Multiple Levels with dirname()

The dirname() function can now accept a second parameter to set how many levels up it will go, meaning you can avoid nesting as shown in Example 4-10.

Example 4-10. Moving up two directories using dirname()
$path = '/foo/bar/bat/baz';
dirname($path, 2); 1
1

This will return /foo/bar.

Salts Deprecated in password_hash()

The salt option for password_hash() has been deprecated, and it will now emit an E_DEPRECATED when used.

Summary

While these changes are small, they all add up to a nicer developer experience, and make the language more consistent.

Get Upgrading to PHP 7 now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.