Programster's Blog

Tutorials focusing on Linux, programming, and open-source

What's New In PHP 8.1

PHP

Below is a list of the features coming out in PHP 8.1, in order of how useful I find them. This is not a definitive list of all changes, but a summary of the biggest and most important changes.

  1. Enums
  2. Readonly Properties
  3. New in Initializers
  4. Pure Intersection Type
  5. Array Unpacking - String Keys
  6. Closures From Callables
  7. Never Return Type
  8. Fsync and FdataSync
  9. Final Class Constants
  10. Fibers

Related Posts

Enums

Enums were brought in with PHP 8.1, and there is too much to cover here, so there is a dedicated PHP enums post.

Readonly Properties

Properties of a class can be marked as readonly. This is great for your immutable value-objects! E.g.

class MyValueObject
{
    private readonly $m_foo;
    private readonly $m_bar;

    public function __construct(string $foo, string $bar)
    {
        $this->m_foo = $foo;
        $this->m_bar = $bar;
    }

    public function getFoo() : string { return $this->m_foo; }
    public function getBar() : string { return $this->m_bar; }
}

New in Initializers

One can now use the new keyword in function definitions in order to create default/optional parameter objects. This is particularly useful for constructors:

class Foo
{
    private $m_logger;

    public funciton __construct(Logger $logger = new MyDefaultLogger())
    {
        $this->m_logger = $logger;
    }
}

... but it is not limited to constructors, you can do this for any function/method.

Pure Intersection Type

This is best demonstrated with code, and makes perfect sense.

You could already use the union type (|) to specify that you allow multiple different types like so:

function getSomething(string|int $key, array $inputs) 
{
    return $inputs[$key];
}

That's fine with basic types, but when one starts diving into the world of interfaces, one may wish to specify that an input matches all of the specified types. E.g.

function foo(InterfaceGetAge & InterfaceGetName $input) 
{
    print "{$input->getName()} is {$input->getAge()} years old.";
}

Check Array Is List

One can now check if an array is a list by using array_is_list. E.g.

array_is_list( ["a", "b", "c"] ); // true
array_is_list( ["1", "2", "3"] ); // true
array_is_list( [1, 2, 3] ); // true
array_is_list( [0, 1, 2, 3] ); // true
array_is_list( [0 => "1", 1 => "2", 2 => "3"] ); // true - indexes line up with normal list
array_is_list( [1 => "1", 2 => "2", 3 => "3"] ); // false - does not start at 0
array_is_list( [0 => "0", 2 => "2"] ); // false - missing index 1 (a gap)

Array Unpacking Now Supports String Keys

Array unpacking with string keys now works because it will now act like performing array_merge in that:

"If the input arrays have the same string keys, then the later value for that key will overwrite the previous one."

Below is an example to demonstrate the point:

$defaultValues = ["bar" => 3, "foo" => 2];
$userPostedFormFields = ["bar" => 4];

$myFunc = function(string $foo, string $bar) { 
    print "foo: {$foo} | bar: {$bar}";
};

$myFunc(...[...$defaultValues, ...$userPostedFormFields]); // "foo: 2 | bar: 4"

The result is because $userPostedFormFields was unpacked after $defaultValues, so the "bar" was overridden to 4. We are also making use of named arguments that came out in PHP 8, so the order of parameters doesn't matter).

Closures From Callables

One can create a closure from a callable through the use of ... like so:

function sum($param1, $param2) { return $param1 + $param2; }

// create a closure for sum, so we can pass it to other things.
$summer = sum(...); 

$value = $summer(1, 2); // 3

This would mean the following is legitimate.

function sum(...$parameters) { 
    $sum =0;

    foreach ($parameters as $parameter)
    {
        $sum += $parameter;
    }

    return $sum;
}

// create a closure for sum, so we can pass it to other things.
$summer = sum(...); 

$parameters1 = [1, 2, 3, 4];
$parameters2 = [5, 6];
$value = $summer(...$parameters1, ...$parameters2); // 21

New Return Type - Never

One can use the keyword never to indicate that a function will never return because it stops the execution flow by throwing an exception or a call to die() or exit() etc.

function dumper(mixed $input): never
{
    die(print_r($input, true));
}

This may seem pointless, but may help other developers understand your code, and apparently useful to static code analysers.

Fsync and FdataSync

PHP 8.1 adds the fsync and fdatasync functions to force synchronization of file changes to disk and ensure operating system write buffers have been flushed before returning.

Final Class Constants

The final keyword can be used to prevent class constants being overridden through inheritance.

class Parent
{
    public final const foo = "foo";
}

class Chile extends Parent
{
    public const foo = "bar"; // this won't work now, and will throw a fatal error.
}

Fibers

Fibers is being introduced in PHP 8.1, but it seems far less useful than I had originally thought. Hence it is at the bottom of this post. Feel free to read up about it with the following links:

References

Last updated: 29th November 2021
First published: 24th November 2021