PHP Logo

PHP 8 was released at the end of November 2020. It’s a major new version that upgrades the language with additional features and performance improvements.

In this article, we’ll look at eight of the biggest enhancements offered by PHP 8. The full list of additions and changes can be found within the official documentation. The docs also include a comprehensive migration guide for use when updating projects from PHP 7.4.

1. Attributes

Attributes, also known as annotations in other languages, provide a mechanism to add metadata to your codebase. Attributes can be used with classes, methods, functions and properties. They’re easier to work with than the docblock approach adopted by many PHP 7 projects.

Attributes are defined as simple classes, themselves annotated with PHP’s built-in Attribute attribute:

class CloudSavvyAttribute {
    protected string $value;
    public function __construct(string $value) {
        $this ->; value = $value;
    public function getValue() : string {
        return $this ->; value;

They can then be attached to entities within your codebase:

class CloudSavvyClass {
    // ...

Attributes are retrieved via the Reflection API. You can inspect and construct attributes defined on a class, method, or other codebase component. Attributes are likely to be most useful within frameworks and libraries, where they’ll help to abstract one-time mapping of app components, such as route definitions and dependency injection wires.

2. Named Arguments

Named Arguments enable you to pass parameters to methods and functions using an array-like construct. This makes it simpler to skip optional parameters and pass them out-of-order.

function foo(?string $a=null, ?string $b=null, ?string $c=null) : void;

In PHP 7, calling the function above while passing the value "demo" to $c required the following invocation:

foo(null, null, "demo");

In PHP 8, the following syntax can be utilised instead:

foo(c: "demo");

This makes function calls with many optional arguments less repetitive and easier to maintain.

3. Constructor Property Promotion

Populating a class’s properties with initial values is one of the most frequent roles of a constructor. Code similar to the following is commonplace in PHP 7 codebases:

class Example {
    protected ?string $Property;
    public function __construct(?string $Property=null) {
        $this ->; Property = $Property;

PHP 8 adds support for Constructor Property Promotion, a shorthand syntax that lets you combine property definition, typehinting, and population inline in the constructor’s signature. The above example could be rewritten as follows:

class Example {
    public function __construct(
        protected string $Property=null

This style removes repetition. Its use makes it easier to add additional constructor properties in the future, reducing the number of code sections you’d need to modify.

4. Union Types

PHP’s type system continues to develop with PHP 8. It’s now possible to hint types as a “union” of two or more types, where the type’s value can derive from any of the types in the union.

public function foo(string|int $bar) : int|float;

In the above contrived example, the foo() function accepts both strings and integers. It will return either an integer or a float.

In practice, this abiliy is likely to be most useful when applied to properties and method parameters—it’s good form to accept a variety of input types and normalise to a well-defined single output type.

5. Match Expression

The new match expression is a terser safer alternative to the well-known switch. It does not require use of case and break statements, supports combined conditions, and returns a value instead of entering a new code block. Type coercion is disabled, so 1.0 (float) is not considered equivalent to "1.0" (string), unlike when using switch.

Here’s a typical PHP 7 switch:

switch (1.0) {
    case 1.0:
        $result = "Float!";
    case "foo":
    case "bar":
        $result = "foobar!";

And, here’s how the same code could look with PHP 8:

$result = match (1.0) {
    1.0 =>; "Float!",
    "foo", "bar" =>; "foobar!"

Once again, the new approach is much more concise. One caveat to point out is that combined conditions syntax values aren’t defined within an array, but rather as a simple comma-delimited set, akin to calling a function.

6. The “Nullsafe” Operator

Another concept borrowed from other languages, PHP 8 now supports inline null checking with automatic short-circuiting. You can build up a chain of checks that will abort, returning null, when the evaluation of any element fails.

In PHP 7:

$photo = null;
if ($user !== null) {
    if ($user ->; profile !== null) {
        if ($user ->; profile ->; getPhoto() !== null) {
            $photo = $user ->; profile ->; getPhoto() ->; getPath();

And in PHP 8:

$photo = $user? ->; profile? ->; getPhoto()? ->; getPath();

PHP 8 again provides a simpler solution, which eliminates nesting. This results in considerably less code to test and maintain.

7. Stricter Type System

We’ve already looked at how Union Types add another layer of flexibility to the PHP 8 type system. A number of additional changes in this area enhance the strictness and consistency with which type checking is enforced.

String to number comparisons are now saner. 0 (integer) is no longer equivalent to "" (empty string) and comparisons such as 123 == "123abc" now evaluate to false, not true. These alterations help reduce the chance of comparison errors within your codebase, although some work might be required to ensure legacy projects are compatible.

The type system has also gained an explicit mixed type (to indicate any kind of value is compatible), as well as a static return type (supporting late static binding). Elsewhere, the signatures of abstract methods in traits are now verified properly.

Altogether, these changes progress PHP’s support for strongly typed programming. Consistent use of type hinting eliminates many bugs that can exist in weakly typed languages, providing developers with greater confidence that the code functions as intended.

8. JIT

The final entry in our list is a more behind-the-scenes capability, rather than a language feature. PHP 8 adds support for Just-In-Time compilation support, which has the potential to significantly enhance performance.

Long-running scripts hosting repetitive tasks are the most likely to benefit from JIT compilation. Benchmarks indicate the improvement will be less pronounced in web applications, where PHP is most commonly found. The addition of the JIT may help PHP to extend into other areas of programming though, enhancing the language’s overall appeal and versatility.

The JIT must be enabled using new settings in the php.ini configuration file. Detailed guidance on the available values and their effects can be found within the documentation; however, the following is advised as a general default:



We’ve only looked at eight of the most significant additions and alterations in PHP 8. It’s worth looking through the official release notes before starting to use PHP 8 in your projects as there’s many more minor features that we’ve been unable to cover here.

Although most changes are backwards compatible, potential gotchas include the type system enhancements and changes within the standard library. You can find the full migration guide on the PHP documentation site.

Profile Photo for James Walker James Walker
James Walker is a contributor to How-To Geek DevOps. He is the founder of Heron Web, a UK-based digital agency providing bespoke software development services to SMEs. He has experience managing complete end-to-end web development workflows, using technologies including Linux, GitLab, Docker, and Kubernetes.
Read Full Bio »