Deprecations & Backward Incompatible Changes PHP versions

Array unpacking with string keys

(PHP 7.4) PHP supports array spread operator ( ...) for array unpacking. An array can be unpacked with another array if the array expression is prefixed with the spread operator. This effectively results in an array_merge of all arrays in the expression.

$array_1 = ['foo', 'bar'];
$array_2 = ['baz', 'qux'];

$array_unpacked = [...$array_1, ...$array_2, ...['quux']];
$array_merged   = array_merge($array_1, $array_2, ['quux']);

var_dump($array_unpacked);
// ['foo', 'bar', 'baz', 'qux', 'quux'];

var_dump($array_merged);
// ['foo', 'bar', 'baz', 'qux', 'quux'];

Prior to (PHP 8.1), the spread operator only supported arrays with numeric keys. Using an array with string key resulted in an error prior to PHP 8.1:

$array = [...['a' => 'foo'], ...['b' => 'bar']];
# Fatal error: Cannot unpack array with string keys in ... on line ...

From (PHP 8.1), array unpacking supports arrays with string keys as well.

$array = [...['a' => 'foo'], ...['b' => 'bar']];
// ['a' => 'foo', 'b' => 'bar'];

source: https://php.watch/versions/8.1/spread-operator-string-array-keys

Enums

(PHP 8.1) Enumerations are a restricting layer on top of classes and class constants, intended to provide a way to define a closed set of possible values for a type.

enum Status
{
    case DRAFT;
    case PUBLISHED;
    case ARCHIVED;
}

class BlogPost
{
    public function __construct(
        public Status $status, 
    ) {}
}

$post = new BlogPost(Status::DRAFT);


Enum methods

enum Status
{
    case DRAFT;
    case PUBLISHED;
    case ARCHIVED;
    
    public function color(): string
    {
        return match($this) 
        {
            Status::DRAFT => 'grey',   
            Status::PUBLISHED => 'green',   
            Status::ARCHIVED => 'red',   
        };
    }
}

$status = Status::ARCHIVED;

$status->color(); // 'red'

source: https://stitcher.io/blog/php-enums

Promoted Properties

(PHP 8.0) property promotion allows you to combine class fields, constructor definition and variable assignments all into one syntax, in the construct parameter list.

Instead of doing this:

class CustomerDTO
{
    public string $name;
    public string $email;
    public DateTimeImmutable $birth_date;
    public function __construct(
        string $name, 
        string $email, 
        DateTimeImmutable $birth_date
    ) {
        $this->name = $name;
        $this->email = $email;
        $this->birth_date = $birth_date;
    }
}

You would write this:

class CustomerDTO
{
    public function __construct(
        public string $name, 
        public string $email, 
        public DateTimeImmutable $birth_date,
    ) {}
}

source: https://stitcher.io/blog/constructor-promotion-in-php-8

Readonly Properties

(PHP 8.1) This makes sure that the public properties couldn’t be overwritten at all

class BlogData
{
    public function __construct(
        public readonly string $title,
        public readonly Status $status,
        public readonly ?DateTimeImmutable $publishedAt = null,
    ) {}
}

source: https://stitcher.io/blog/php-81-readonly-properties

(PHP 8.2) Whole class can be made readonly

readonly class BlogData
{
    public function __construct(
        public string $title,
        public Status $status,
        public ?DateTimeImmutable $publishedAt = null,
    ) {}
}

source: https://stitcher.io/blog/readonly-classes-in-php-82

Pure Intersection Types (&)

(PHP 8.1) supports Intersection Types, which allows declaring a type for a parameter, property, or return types and enforce that values belong to all of the declared class/interface types. This is the opposite of Union Types, which allows any of the declared types. PHP 8.1’s implementation of Intersection Types is called “pure” Intersection Types because combining Union Types and Intersection Types in the same declaration is not allowed.

function count_and_iterate(Iterator&\Countable $value) {
    foreach($value as $val) {}
    count($value);
}

source: https://php.watch/versions/8.1/intersection-types

Never return type

(PHP 8.1) A function/method that is declared with the never return type indicates that it will never return a value, and always throws an exception or terminates with a die/exit call.

never return type is similar to the existing void return type, but the never type guarantees that the program will terminate or throw. In other words, a function/method declared never must not call return at all, not even in the return; form.

function redirect(string $url): never {
    header('Location: ' . $url);
    exit();
}

source: https://php.watch/versions/8.1/never-return-type

array_is_list

(PHP 8.1) brings a new function array_is_list, that returns whether a given array is an array with all sequential integers starting from 0.

In other words, this function returns true if the given array is semantic list of values; an array with all keys are integers, keys start from 0, with no gaps in between.

array_is_list function returns true on empty arrays as well.

array_is_list([]); // true
array_is_list([1, 2, 3]); // true
array_is_list(['apple', 2, 3]); // true
array_is_list(['apple', 'orange']); // true
array_is_list([0 => 'apple', 'orange']); // true
array_is_list([0 => 'apple', 1 => 'orange']); // true

// Key does not start with 0
array_is_list([1 => 'apple', 'orange']); // false

// Keys are not in order
array_is_list([1 => 'apple', 0 => 'orange']); // false

// Non-integer keys
array_is_list([0 => 'apple', 'foo' => 'bar']); false

// Non-sequential keys
array_is_list([0 => 'apple', 2 => 'bar']); false

source: https://php.watch/versions/8.1/array_is_list

First Class Callable

(PHP 8.1) and later supports a new syntax in creating a callable from within the current scope. With this new syntax, it is easier to create a callable using the same syntax a function/method is called, instead of using Closure::fromCallable.

Closure::fromCallable returns a callable (Closure object) from a PHP callable (function name, method, or anonymous function). The first-class callable syntax aims to reduce the boilerplate code of Closure::fromCallable.

// old
$callable = Closure::fromCallable('strtoupper');
// new
$callable = strtoupper(...);
echo $callable('foo'); // FOO

source: https://php.watch/versions/8.1/first-class-callable-syntax

new in initializers

(PHP 8.1) now you can directly initialize a class in default value

class MyStateMachine
{
    public function __construct(
        private State $state = new InitialState(),
    ) {
    }
}

source: https://stitcher.io/blog/php-81-new-in-initializers

Final Class Constant

(PHP 8.1) Constants declared on PHP classes can be overridden by sub classes. Prior to PHP 8.1, the final flag was not allowed on class constants, which would have protected class constants from being overridden by sub classes. Attempting to use the final flag on class constants resulted in a fatal error.

In PHP 8.1 and later, the final flag is allowed on class/interface constants, and none of the sub classes are allowed to extend/override final constants.

class Foo {
    final public const TEST = '1';
}
class Bar extends Foo {
    public const TEST = '2';
}
# Fatal error: Bar::TEST cannot override final constant Foo::TEST in %s on line %d

source: https://php.watch/versions/8.1/final-class-const

«
»

Leave a Reply

Your email address will not be published. Required fields are marked *