PHP 7.4 is scheduled for release in November of this year, with it bring some performance improvements along with some new features. Here are a couple of the new features that are coming that I'm excited about.

Spread operator updates

PHP has had support for the spread operator for a while. It's functionality has been limited to unpacking functional arguments. For example. You've been able to do the following since PHP 5.6.

<?php
function spreadArgs(...$args) {
  print_r($args);
}

spreadArgs(...[1, 2, 3, 4]);
spreadArgs(1, 2, 3, 4);

/*
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
)
*/

This new RFC will add spread functionality to the array expression. That means unpacking arrays inline like so

<?php
$vine_veges = ['cucumber', 'pumpkin'];
$ground_veges = ['carrots', 'potatos'];

print_r(['eggplant', ...$vine_veges, ...$ground_veges]);

/*
Array
(
    [0] => eggplant
    [1] => cucumber
    [2] => pumpkin
    [3] => carrots
    [4] => potatos
)
*/

This unpacking works with both array() and [] syntax. You can also unpack arrays returned directly from functions.

<?php
function get_colours($additional_colours = []) {
  return ['red', 'green', 'blue', ...$additional_colours];
}

print_r(['yellow', ...get_colours(['purple', 'green']), 'black']);

/*
Array
(
    [0] => yellow
    [1] => red
    [2] => green
    [3] => blue
    [4] => purple
    [5] => green
    [6] => black
)
*/

The unpacking syntax doesn't work with associative arrays. So it's not as flexible as it's Javascript counterpart.

Arrow functions

While PHP has supported closures for some time, they tend to be quite verbose. This RFC adds arrow functions and short function syntax to PHP. Take this code example from the RFC.

function array_values_from_keys($arr, $keys) {
    return array_map(function ($x) use ($arr) { return $arr[$x]; }, $keys);
}

With the new syntax this can be shortened to be

function array_values_from_keys($arr, $keys) {
    return array_map(fn($x) => $arr[$x], $keys);
}

Few things to notice there, there's a new shortened function fn operator, also the scoping has been simplified so that the variable $arr is in scope to the function without the need for the use statement.

I'm genuinely excited about this as I find this code.

/* inline */
array_filter(range(0, 1024), fn($b) => $b % 64 === 0);

/* variable function */
$factor = fn($number) => $number % 64 === 0;
array_filter(range(0, 1024), $factor);

A lot cleaner than these variants.

/* inline */
array_filter(range(0, 1024), function($b) { 
  return $b % 64 === 0;
});

/* variable function */
$factor = function($number) {
  return $number % 64 === 0;
}
array_filter(range(0, 1024), $factor);

Typed properties

PHP has supported types in some form or another for quite a while. Argument types have been a staple since version 5 and since version 7, PHP also supports return types. It'spretty standard to see class definitions like this.

class MyClass {

  /* int */
  protected $count = null;
  
  /* MyClass */
  protected $sibling;
  
  /**
   * @param $sibling MyClass
   * @return array
   */
  public function addSibling(MyClass $sibling): array
  {
  	$this->sibling = $sibling;
    return [
      'count' => $this->count++,
      'current_sibling' => $this->sibling
    ];
  }
}

With typed properties we'll also be able to define the types of the class properties.

class MyClass {

  protected ?int $count = null;
  
  protected MyClass $sibling;
  
  /* ... */
}

This improves code readability and will also help debugging and IDE support.

Currently the supported types are.

  • int
  • bool
  • float
  • string
  • array
  • object
  • iterable
  • self
  • parent
  • any class or interface name
  • ?type where type may be any of the above.

The preceding ? tells the run-time interpreter that the property can be null.

There's a lot more to typed properties than I've covered here so go and have a read over at the RFC page.

Null Coalescing Assignment

PHP 7 introduced the Null Coalescing Operator as a shorthand for common usage of the ternary operator. As per the documentation:

The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
<?php
// Fetches the value of $_GET['user'] and returns 'nobody'
// if it does not exist.
$username = $_GET['user'] ?? 'nobody';
// This is equivalent to:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// Coalescing can be chained: this will return the first
// defined value out of $_GET['user'], $_POST['user'], and
// 'nobody'.
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

The Null Coalescing Assignment Operator takes this a step further. Consider the case of defining defaults.

/* Standard Conditional */
function setName($name = null) {
  if (!$name) {
    $name = 'default';
  }
  /* ... */
}

/* Ternary (Elvis Operator) */
function setName($name = null) {
  $name = $name ?: 'default';
  /* ... */
}

/* Null Coalescing */
function setName($name = null) {
  $name = $name ?? 'default';
  /* ... */
}

/* Null Coalescing Assignment */
function setName($name = null) {
  $name ??= 'default';
  /* ... */
}

As you can see the syntax is a lot cleaner. Another benefit is that it's safe to undefined values.

<?php
$details = [[], ['category' => 'Red']];

/* Ternary/Elvis */
$details[0]['category'] = $details[0]['category'] ?: 'Blue';

// PHP Notice:  Undefined index: category in php shell code on line 1


/* Null Coalescing */
$details[0]['category'] = $details[0]['category'] ?? 'Blue';

// 'Blue'


/* Null Coalescing Assignment */
$details[0]['category'] ??= 'Blue';

// 'Blue'

One more

I'm not a massive fan of all the new features. Take, for example the Numeric Literal Separator.

This feature enables the ability to make numeric literals easier to read for developers. By adding an underscore separator to Numerical Literals. The underscore is removed during runtime so is ignored by the interpreter. It's completely optional.

// a billion!
(1000000000 === 1_000_000_000) // true

// scale is hundreds of millions
(107925284.88 === 107_925_284.88) // true

// $135, stored as cents
(13500 === 135_00) // true

While I appreciate that it makes the intention of the original developer easier to decode, this one seems a tad strange to me.

Conclusion

These are the features I'm most looking forward to, let me know in the comments what you think, or if there are other features you'd like to see in PHP in the future.

7.4 isn't due till November 28th 2019. In the meantime if you want to have a play with some of the new features you can use the interactive PHP interpreter via docker.

docker run -it php:7.4-rc-cli -a

Have fun.