PHP 8: Modern PHP Development · Modern PHP Syntax & Types

The PHP 8 Type System

Scalar, union, nullable, intersection, mixed, never and DNF types.

PHP 8 lets you declare types for parameters, return values and properties. Beyond scalars (int, float, string, bool) and classes you get union types (int|string, 8.0), mixed (8.0), static returns (8.0), never for functions that always throw or exit (8.1), intersection types (Countable&Iterator, 8.1), standalone null, false and true types (8.2) and DNF types like (A&B)|null (8.2).

Types document intent, catch bugs early, and let static analyzers (PHPStan, Psalm) and IDEs reason about your code.

<?php
declare(strict_types=1);

function parseId(int|string $id): int
{
    return is_int($id) ? $id : (int) $id;
}

/** @param array<int, User> $users */
function findUser(array $users, int $id): ?User   // nullable: User|null
{
    return $users[$id] ?? null;
}

function fail(string $message): never      // never returns normally
{
    throw new DomainException($message);
}

function process((Countable&Traversable)|null $items): void { /* DNF type */ }

Common pitfalls

  • Using mixed everywhere — it disables most benefits of typing.
  • Confusing ?T (nullable) with an optional parameter; ?int $x still requires an argument unless it has a default.
  • Assuming types are checked inside arrays — array says nothing about element types (use PHPDoc generics like list<User> for analyzers).

Key points

  • Union, intersection and DNF types make signatures precise
  • never marks functions that always throw/exit
  • Use PHPDoc generics for array element types

Further reading: PHP manual: type declarations

Practice questions

What is the difference between ?string and string|null?

Answer

None — ?string is shorthand for string|null. The ? shorthand can't be combined with other union members, so int|string|null must be written in full.

When would you use the never return type?

Answer

For functions that never return normally: they always throw an exception or call exit(). It helps static analysis understand that code after the call is unreachable, e.g. a fail() or redirect() helper.

Open in the app to mark lessons complete, take notes and track your progress.