You are on page 1of 29

25/01/2021 What's new in PHP 8 - stitcher.

io

Scout APM helps PHP developers pinpoint N+1 queries, memory leaks & more so you
can troubleshoot fast & get back to coding faster. Start your free 14-day trial today.

« back — written by Brent on November 26, 2020

What's new in PHP 8

PHP 8 is here! It was released on November 26, 2020. You can download it
here. It's a new major version, which means that it will introduce some
breaking changes, as well as lots of new features and performance
improvements.

StackPulse is the future of running reliable software in


production. Try it for free!
ads via Carbon

Because of the breaking changes, there's a higher chance you'll need to


make some changes in your code to get it running on PHP 8. If you've kept
up to date with the latest releases though, the upgrade shouldn't be too
hard, since most breaking changes were deprecated before in the 7.*
versions. And don't worry, all these deprecations are listed in this post.

Besides breaking changes, PHP 8 also brings a nice set of new features
such as the JIT compiler, union types, attributes, and more.

New features
Let's start with all new features, it's quite a list!

https://stitcher.io/blog/new-in-php-8 1/29
25/01/2021 What's new in PHP 8 - stitcher.io

Union types rfc

Given the dynamically typed nature of PHP, there are lots of cases where
union types can be useful. Union types are a collection of two or more
types which indicate that either one of those can be used.

public function foo(Foo|Bar $input): int|float;

Note that void can never be part of a union type, since it indicates "no
return value at all". Furthermore, nullable unions can be written using
|null , or by using the existing ? notation:

public function foo(Foo|null $foo): void;

public function bar(?Bar $bar): void;

JIT rfc

The JIT — just in time — compiler promises significant performance


improvements, albeit not always within the context of web requests. I've
done my own benchmarks on real-life web applications, and it seems like
the JIT doesn't make that much of a difference, if any, on those kinds of
PHP projects.

https://stitcher.io/blog/new-in-php-8 2/29
25/01/2021 What's new in PHP 8 - stitcher.io

If you want to know more about what the JIT can do for PHP, you can read
another post I wrote about it here.

Interested in more?
I'm writing a new series on how I manage and grow my blog called "Blogs for
Devs". You might like the behind the scenes stories and also be inspired to
start your own blog.

Check it out!

The nullsafe operator rfc

If you're familiar with the null coalescing operator you're already familiar
with its shortcomings: it doesn't work on method calls. Instead you need
intermediate checks, or rely on optional helpers provided by some
frameworks:

$startDate = $booking->getStartDate();

$dateAsString = $startDate ? $startDate->asDateTimeString() : null;

https://stitcher.io/blog/new-in-php-8 3/29
25/01/2021 What's new in PHP 8 - stitcher.io

With the addition of the nullsafe operator, we can now have null coalescing-
like behaviour on methods!

$dateAsString = $booking->getStartDate()?->asDateTimeString();

You can read all about the nullsafe operator here.

Named arguments rfc

Named arguments allow you to pass in values to a function, by specifying


the value name, so that you don't have to take their order into
consideration, and you can also skip optional parameters!

function foo(string $a, string $b, ?string $c = null, ?string $d = null)


{ /* … */ }

foo(
b: 'value b',
a: 'value a',
d: 'value d',
);

You can read about them in-depth in this post.

https://stitcher.io/blog/new-in-php-8 4/29
25/01/2021 What's new in PHP 8 - stitcher.io

Attributes rfc

Attributes, commonly known as annotations in other languages, offers a


way to add meta data to classes, without having to parse docblocks.

As for a quick look, here's an example of what attributes look like, from the
RFC:

use App\Attributes\ExampleAttribute;

#[ExampleAttribute]
class Foo
{
#[ExampleAttribute]
public const FOO = 'foo';

#[ExampleAttribute]
public $x;

#[ExampleAttribute]
public function foo(#[ExampleAttribute] $bar) { }
}

#[Attribute]
class ExampleAttribute
{
public $value;

public function __construct($value)


{
$this->value = $value;

https://stitcher.io/blog/new-in-php-8 5/29
25/01/2021 What's new in PHP 8 - stitcher.io

}
}

Note that this base Attribute used to be called PhpAttribute in the


original RFC, but was changed with another RFC afterwards. If you want to
take a deep dive in how attributes work, and how you can build your own;
you can read about attributes in depth on this blog.

Noticed a tpyo? You can submit a PR to fix it. If you want to stay up to date
about what's happening on this blog, you can follow me on Twitter or
subscribe to my newsletter:
Email Subscribe

Match expression rfc

You could call it the big brother of the switch expression: match can
return values, doesn't require break statements, can combine conditions,
uses strict type comparisons and doesn't do any type coercion.

It looks like this:

$result = match($input) {
0 => "hello",
'1', '2', '3' => "world",
};

You can read up on the match expression in detail, over here.

https://stitcher.io/blog/new-in-php-8 6/29
25/01/2021 What's new in PHP 8 - stitcher.io

Constructor property promotion rfc

This RFC adds syntactic sugar to create value objects or data transfer
objects. Instead of specifying class properties and a constructor for them,
PHP can now combine them into one.

Instead of doing this:

class Money
{
public Currency $currency;

public int $amount;

public function __construct(


Currency $currency,
int $amount,
) {
$this->currency = $currency;
$this->amount = $amount;
}
}

You can now do this:

class Money
{
public function __construct(
public Currency $currency,
public int $amount,

https://stitcher.io/blog/new-in-php-8 7/29
25/01/2021 What's new in PHP 8 - stitcher.io

) {}
}

There's a lot more to tell about property promotion, you can read about
them in this dedicated post.

New static return type rfc

While it was already possible to return self , static wasn't a valid return
type until PHP 8. Given PHP's dynamically typed nature, it's a feature that
will be useful to many developers.

class Foo
{
public function test(): static
{
return new static();
}
}

New mixed type rfc

Some might call it a necessary evil: the mixed type causes many to have
mixed feelings. There's a very good argument to make for it though: a
missing type can mean lots of things in PHP:

https://stitcher.io/blog/new-in-php-8 8/29
25/01/2021 What's new in PHP 8 - stitcher.io

A function returns nothing or null


We're expecting one of several types
We're expecting a type that can't be type hinted in PHP

Because of the reasons above, it's a good thing the mixed type is added.
mixed itself means one of these types:

array

bool

callable

int

float

null

object

resource

string

Note that mixed can also be used as a parameter or property type, not just
as a return type.

Also note that since mixed already includes null , it's not allowed to make
it nullable. The following will trigger an error:

// Fatal error: Mixed types cannot be nullable, null is already part of the m
function bar(): ?mixed {}

https://stitcher.io/blog/new-in-php-8 9/29
25/01/2021 What's new in PHP 8 - stitcher.io

Throw expression rfc

This RFC changes throw from being a statement to being an expression,


which makes it possible to throw exception in many new places:

$triggerError = fn () => throw new MyError();

$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');

Inheritance with private methods rfc

Previously, PHP used to apply the same inheritance checks on public,


protected and private methods. In other words: private methods should
follow the same method signature rules as protected and public methods.
This doesn't make sense, since private methods won't be accessible by
child classes.

This RFC changed that behaviour, so that these inheritance checks are not
performed on private methods anymore. Furthermore, the use of final
private function also didn't make sense, so doing so will now trigger a
warning:

Warning: Private methods cannot be final as they are never overridden by othe

https://stitcher.io/blog/new-in-php-8 10/29
25/01/2021 What's new in PHP 8 - stitcher.io

Weak maps rfc

Built upon the weakrefs RFC that was added in PHP 7.4, a WeakMap
implementation is added in PHP 8. WeakMap holds references to objects,
which don't prevent those objects from being garbage collected.

Take the example of ORMs, they often implement caches which hold
references to entity classes to improve the performance of relations
between entities. These entity objects can not be garbage collected, as
long as this cache has a reference to them, even if the cache is the only
thing referencing them.

If this caching layer uses weak references and maps instead, PHP will
garbage collect these objects when nothing else references them anymore.
Especially in the case of ORMs, which can manage several hundreds, if not
thousands of entities within a request; weak maps can offer a better, more
resource friendly way of dealing with these objects.

Here's what weak maps look like, an example from the RFC:

class Foo
{
private WeakMap $cache;

public function getSomethingWithCaching(object $obj): object


{
return $this->cache[$obj]
??= $this->computeSomethingExpensive($obj);
}
}

https://stitcher.io/blog/new-in-php-8 11/29
25/01/2021 What's new in PHP 8 - stitcher.io

Allowing ::class on objects rfc

A small, yet useful, new feature: it's now possible to use ::class on
objects, instead of having to use get_class() on them. It works the same
way as get_class() .

$foo = new Foo();

var_dump($foo::class);

Non-capturing catches rfc

Whenever you wanted to catch an exception before PHP 8, you had to


store it in a variable, regardless whether you used that variable or not. With
non-capturing catches, you can omit the variable, so instead of this:

try {
// Something goes wrong
} catch (MySpecialException $exception) {
Log::error("Something went wrong");
}

You can now do this:

https://stitcher.io/blog/new-in-php-8 12/29
25/01/2021 What's new in PHP 8 - stitcher.io

try {
// Something goes wrong
} catch (MySpecialException) {
Log::error("Something went wrong");
}

Note that it's required to always specify the type, you're not allowed to have
an empty catch . If you want to catch all exceptions and errors, you can
use Throwable as the catching type.

Trailing comma in parameter lists rfc

Already possible when calling a function, trailing comma support was still
lacking in parameter lists. It's now allowed in PHP 8, meaning you can do
the following:

public function(
string $parameterA,
int $parameterB,
Foo $objectfoo,
) {
// …
}

As a sidenote: trailing commas are also supported in the use list of


closures, this was an oversight and now added via a separate RFC.

https://stitcher.io/blog/new-in-php-8 13/29
25/01/2021 What's new in PHP 8 - stitcher.io

Create DateTime objects from interface


You can already create a DateTime object from a DateTimeImmutable object
using DateTime::createFromImmutable($immutableDateTime) , but the other
way around was tricky. By adding DateTime::createFromInterface() and
DatetimeImmutable::createFromInterface() there's now a generalised way to
convert DateTime and DateTimeImmutable objects to each other.

DateTime::createFromInterface(DateTimeInterface $other);

DateTimeImmutable::createFromInterface(DateTimeInterface $other);

New Stringable interface rfc

The Stringable interface can be used to type hint anything that


implements __toString() . Whenever a class implements __toString() , it
automatically implements the interface behind the scenes and there's no
need to manually implement it.

class Foo
{
public function __toString(): string
{
return 'foo';
}
}

https://stitcher.io/blog/new-in-php-8 14/29
25/01/2021 What's new in PHP 8 - stitcher.io

function bar(string|Stringable $stringable) { /* … */ }

bar(new Foo());
bar('abc');

New str_contains() function rfc

Some might say it's long overdue, but we finally don't have to rely on
strpos() anymore to know whether a string contains another string.

Instead of doing this:

if (strpos('string with lots of words', 'words') !== false) { /* … */ }

You can now do this

if (str_contains('string with lots of words', 'words')) { /* … */ }

New str_starts_with() and str_ends_with() functions rfc

Two other ones long overdue, these two functions are now added in the
core.

https://stitcher.io/blog/new-in-php-8 15/29
25/01/2021 What's new in PHP 8 - stitcher.io

str_starts_with('haystack', 'hay'); // true


str_ends_with('haystack', 'stack'); // true

New fdiv() function pr

The new fdiv() function does something similar as the fmod() and
intdiv() functions, which allows for division by 0. Instead of errors you'll
get INF , -INF or NAN , depending on the case.

New get_debug_type() function rfc

get_debug_type() returns the type of a variable. Sounds like something


gettype() would do? get_debug_type() returns more useful output for
arrays, strings, anonymous classes and objects.

For example, calling gettype() on a class \Foo\Bar would return object .


Using get_debug_type() will return the class name.

A full list of differences between get_debug_type() and gettype() can be


found in the RFC.

New get_resource_id() function pr

https://stitcher.io/blog/new-in-php-8 16/29
25/01/2021 What's new in PHP 8 - stitcher.io

Resources are special variables in PHP, referring to external resources.


One example is a MySQL connection, another one a file handle.

Each one of those resources gets assigned an ID, though previously the
only way to know that id was to cast the resource to int :

$resourceId = (int) $resource;

PHP 8 adds the get_resource_id() functions, making this operation more


obvious and type-safe:

$resourceId = get_resource_id($resource);

Abstract methods in traits improvements rfc

Traits can specify abstract methods which must be implemented by the


classes using them. There's a caveat though: before PHP 8 the signature of
these method implementations weren't validated. The following was valid:

trait Test {
abstract public function test(int $input): int;
}

class UsesTrait
{
use Test;

https://stitcher.io/blog/new-in-php-8 17/29
25/01/2021 What's new in PHP 8 - stitcher.io

public function test($input)


{
return $input;
}
}

PHP 8 will perform proper method signature validation when using a trait
and implementing its abstract methods. This means you'll need to write this
instead:

class UsesTrait
{
use Test;

public function test(int $input): int


{
return $input;
}
}

Object implementation of token_get_all() rfc

The token_get_all() function returns an array of values. This RFC adds a


PhpToken class with a PhpToken::tokenize() method. This implementation
works with objects instead of plain values. It consumes less memory and is
easier to read.

https://stitcher.io/blog/new-in-php-8 18/29
25/01/2021 What's new in PHP 8 - stitcher.io

Variable syntax tweaks rfc

From the RFC: "the Uniform Variable Syntax RFC resolved a number of
inconsistencies in PHP's variable syntax. This RFC intends to address a
small handful of cases that were overlooked."

Type annotations for internal functions externals

Lots of people pitched in to add proper type annotations to all internal


functions. This was a long standing issue, and finally solvable with all the
changes made to PHP in previous versions. This means that internal
functions and methods will have complete type information in reflection.

ext-json always available rfc

Previously it was possible to compile PHP without the JSON extension


enabled, this is not possible anymore. Since JSON is so widely used, it's
best developers can always rely on it being there, instead of having to
ensure the extension exist first.

Breaking changes
As mentioned before: this is a major update and thus there will be breaking
changes. The best thing to do is take a look at the full list of breaking
changes over at the UPGRADING document.
https://stitcher.io/blog/new-in-php-8 19/29
25/01/2021 What's new in PHP 8 - stitcher.io

Many of these breaking changes have been deprecated in previous 7.*


versions though, so if you've been staying up-to-date over the years, it
shouldn't be all that hard to upgrade to PHP 8.

Consistent type errors rfc

User-defined functions in PHP will already throw TypeError , but internal


functions did not, they rather emitted warnings and returned null . As of
PHP 8 the behaviour of internal functions have been made consistent.

Reclassified engine warnings rfc

Lots of errors that previously only triggered warnings or notices, have been
converted to proper errors. The following warnings were changed.

Undefined variable: Error exception instead of notice


Undefined array index: warning instead of notice
Division by zero: DivisionByZeroError exception instead of warning
Attempt to increment/decrement property '%s' of non-object: Error
exception instead of warning
Attempt to modify property '%s' of non-object: Error exception instead
of warning
Attempt to assign property '%s' of non-object: Error exception instead
of warning
Creating default object from empty value: Error exception instead of
warning
https://stitcher.io/blog/new-in-php-8 20/29
25/01/2021 What's new in PHP 8 - stitcher.io

Trying to get property '%s' of non-object: warning instead of notice


Undefined property: %s::$%s: warning instead of notice
Cannot add element to the array as the next element is already
occupied: Error exception instead of warning
Cannot unset offset in a non-array variable: Error exception instead of
warning
Cannot use a scalar value as an array: Error exception instead of
warning
Only arrays and Traversables can be unpacked: TypeError exception
instead of warning
Invalid argument supplied for foreach(): TypeError exception instead
of warning
Illegal offset type: TypeError exception instead of warning
Illegal offset type in isset or empty: TypeError exception instead of
warning
Illegal offset type in unset: TypeError exception instead of warning
Array to string conversion: warning instead of notice
Resource ID#%d used as offset, casting to integer (%d): warning
instead of notice
String offset cast occurred: warning instead of notice
Uninitialized string offset: %d: warning instead of notice
Cannot assign an empty string to a string offset: Error exception
instead of warning
Supplied resource is not a valid stream resource: TypeError exception
instead of warning

https://stitcher.io/blog/new-in-php-8 21/29
25/01/2021 What's new in PHP 8 - stitcher.io

The @ operator no longer silences fatal errors


It's possible that this change might reveal errors that again were hidden
before PHP 8. Make sure to set display_errors=Off on your production
servers!

Default error reporting level


It's now E_ALL instead of everything but E_NOTICE and E_DEPRECATED . This
means that many errors might pop up which were previously silently
ignored, though probably already existent before PHP 8.

Default PDO error mode rfc

From the RFC: The current default error mode for PDO is silent. This
means that when an SQL error occurs, no errors or warnings may be
emitted and no exceptions thrown unless the developer implements their
own explicit error handling.

This RFC changes the default error will change to PDO::ERRMODE_EXCEPTION


in PHP 8.

Concatenation precedence rfc

While already deprecated in PHP 7.4, this change is now taken into effect.
If you'd write something like this:
https://stitcher.io/blog/new-in-php-8 22/29
25/01/2021 What's new in PHP 8 - stitcher.io

echo "sum: " . $a + $b;

PHP would previously interpret it like this:

echo ("sum: " . $a) + $b;

PHP 8 will make it so that it's interpreted like this:

echo "sum: " . ($a + $b);

Stricter type checks for arithmetic and bitwise


operators rfc
Before PHP 8, it was possible to apply arithmetic or bitwise operators on
arrays, resources or objects. This isn't possible anymore, and will throw a
TypeError :

[] % [42];
$object + 4;

https://stitcher.io/blog/new-in-php-8 23/29
25/01/2021 What's new in PHP 8 - stitcher.io

Namespaced names being a single token rfc

PHP used to interpret each part of a namespace (separated by a backslash


\ ) as a sequence of tokens. This RFC changed that behaviour, meaning
reserved names can now be used in namespaces.

Saner numeric strings rfc

PHP's type system tries to do a lot of smart things when it encounters


numbers in strings. This RFC makes that behaviour more consistent and
clear.

Saner string to number comparisons rfc

This RFC fixes the very strange case in PHP where 0 == "foo" results in
true . There are some other edge cases like that one, and this RFC fixes
them.

Reflection changes
A few reflection methods have been deprecated:

ReflectionFunction::isDisabled()

ReflectionParameter::getClass()

ReflectionParameter::isCallable()

https://stitcher.io/blog/new-in-php-8 24/29
25/01/2021 What's new in PHP 8 - stitcher.io

You should now use ReflectionType to get information about a parameter's


type:

$reflectionParameter->getType()->allowsNull();

If the type is a single type, ReflectionParameter::getType() returns an


instance of ReflectionNamedType , which you can get its name from and
whether it's built-in:

$reflectionParameter->getType()->getName();
$reflectionParameter->getType()->isBuiltin();

If the type is a union type however, you'll get an instance of


ReflectionUnionType , which can give you an array of ReflectionNamedType
like so:

$reflectionParameter->getType()->getTypes();

Checking whether a type is a union or not can be done with an instanceof


check:

if ($reflectionParameter->getType() instanceof ReflectionNamedType) {


// It's a single type
}

if ($reflectionParameter->getType() instanceof ReflectionUnionType) {

https://stitcher.io/blog/new-in-php-8 25/29
25/01/2021 What's new in PHP 8 - stitcher.io

// It's a union type


}

Next up, three method signatures of reflection classes have been changed:

ReflectionClass::newInstance($args);
ReflectionFunction::invoke($args);
ReflectionMethod::invoke($object, $args);

Have now become:

ReflectionClass::newInstance(...$args);
ReflectionFunction::invoke(...$args);
ReflectionMethod::invoke($object, ...$args);

The upgrading guide specifies that if you extend these classes, and still
want to support both PHP 7 and PHP 8, the following signatures are
allowed:

ReflectionClass::newInstance($arg = null, ...$args);


ReflectionFunction::invoke($arg = null, ...$args);
ReflectionMethod::invoke($object, $arg = null, ...$args);

https://stitcher.io/blog/new-in-php-8 26/29
25/01/2021 What's new in PHP 8 - stitcher.io

Interested in more?
I'm writing a new series on how I manage and grow my blog called "Blogs for
Devs". You might like the behind the scenes stories and also be inspired to
start your own blog.

Check it out!

Stable sorting rfc

Before PHP 8, sorting algorithms were unstable. This means that the order
of equal elements wasn't guaranteed. PHP 8 changes the behaviour of all
sorting functions to stable sorting.

Fatal error for incompatible method signatures rfc

From the RFC: Inheritance errors due to incompatible method signatures


currently either throw a fatal error or a warning depending on the cause of
the error and the inheritance hierarchy.

Other deprecations and changes

https://stitcher.io/blog/new-in-php-8 27/29
25/01/2021 What's new in PHP 8 - stitcher.io

During the PHP 7.* development, several deprecations were added that are
now finalised in PHP 8.

Deprecations in PHP 7.2


Deprecations in PHP 7.3
Deprecations in PHP 7.4
Locale-independent float to string cast

Noticed a tpyo? You can submit a PR to fix it. If you want to stay up to date
about what's happening on this blog, you can follow me on Twitter or
subscribe to my newsletter:
Email Subscribe

Footnotes
Upgrading to PHP 8 using Homebrew on a Mac
The nullsafe operator
The match operator in PHP 8
Named arguments in PHP 8
Property promotion in PHP 8
The latest PHP version — how modern PHP versions are managed
Attributes in PHP 8 — A close look at attributes, also known as
annotations
PHP in 2020
What's new in PHP 7.4
What's new in PHP 7.3

https://stitcher.io/blog/new-in-php-8 28/29
25/01/2021 What's new in PHP 8 - stitcher.io

Next up: Announcing Blogs for Devs

Follow me: Twitter — RSS — Newsletter — Patreon — GitHub

© 2021 stitcher.io — Cookies & Privacy

https://stitcher.io/blog/new-in-php-8 29/29

You might also like