Mixed and Never Types

Ma Mariya Vinciya Updated 21 Oct 2026
6 min read ·Lesson 165 of 174
In this post

PHP's type system includes two special types at opposite ends: mixed , which accepts every value, and never , which describes a function that never returns at all. Both make code more explicit: mixed

PHP's type system includes two special types at opposite ends: mixed, which accepts every value, and never, which describes a function that never returns at all. Both make code more explicit: mixed documents that "any value" is intentional, and never documents that a function always stops execution by throwing an exception or exiting.

TypeIntroducedMeaning
mixedPHP 8.0Any value: int, float, string, bool, array, object, callable, resource, or null
neverPHP 8.1The function never returns normally (return type only)

 


The mixed Type

What It Means

In simple terms: mixed says "this can be anything". It is used where a function genuinely works with values of any type — a cache that stores anything, a configuration reader, a debugging helper.

Technically: mixed is equivalent to the union of all types: array|bool|callable|int|float|null|object|resource|string. It can be used for parameters, return types, and properties.

Example: A Configuration Store

<?php
final class Config
{
    public function __construct(private array $values) {}

    public function get(string $key, mixed $default = null): mixed
    {
        return $this->values[$key] ?? $default;
    }
}

$config = new Config([
    'app_name' => 'GoCourse',
    'per_page' => 20,
    'debug' => false,
    'languages' => ['en', 'ta'],
]);

foreach (['app_name', 'per_page', 'debug', 'languages', 'timezone'] as $key) {
    echo str_pad($key, 10) . get_debug_type($config->get($key, 'Asia/Kolkata')) . "\n";
}

 

Output

app_name  string
per_page  int
debug     bool
languages array
timezone  string

 

  • Configuration values can be strings, integers, booleans, or arrays, so mixed is honest.
  • timezone is missing, so the default ('Asia/Kolkata') is returned.
  • debug is false, and ?? keeps it, because ?? only replaces null — not false.

mixed vs No Type

DeclarationMeaning
function get($key)No information: maybe the author forgot to add a type
function get(mixed $key)Explicit: any type is intentionally accepted

 

With a mixed return type, the function must return a value explicitly. A bare return; is a compile error, because mixed expects a value (write return null; instead).

Rules for mixed

RuleReason
?mixed is invalidmixed already includes null
mixed cannot be part of a union (`mixedint`)It already includes every type
A child class may widen a parameter to mixedContravariance: accepting more is allowed
A child class may narrow a mixed return type (for example, to string)Covariance: returning something more specific is allowed

 

Use mixed Sparingly

A mixed value gives no guarantees: code receiving it must check the type before using it (is_string(), is_array(), …). Prefer specific types or unions whenever the possible types are known. mixed is appropriate for generic infrastructure — caches, containers, serializers, configuration — not for business logic.


The never Type

What It Means

In simple terms: A function with the return type never promises that it will never finish normally. Calling it always ends with an exception being thrown, the script exiting, or an endless loop. It is used for helpers such as abort(), redirect(), or fail().

Technically: never is a bottom type: no value has this type. It can only be used as a return type and cannot be combined with other types. If a never function returns — even implicitly by reaching its end — PHP throws a TypeError.

Example: Validation Helpers

<?php
function fail(string $message): never
{
    throw new InvalidArgumentException($message);
}

function parseQuantity(string $input): int
{
    $quantity = filter_var($input, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 99]]);

    if ($quantity === false) {
        fail("Invalid quantity: $input");
    }

    return $quantity;
}

foreach (['3', 'ten', '150'] as $input) {
    try {
        echo "Quantity: " . parseQuantity($input) . "\n";
    } catch (InvalidArgumentException $e) {
        echo "Error: " . $e->getMessage() . "\n";
    }
}

 

Output

Quantity: 3
Error: Invalid quantity: ten
Error: Invalid quantity: 150

 

Why never Helps

  1. The signature tells readers that fail() always stops the current flow; no one needs to read its body to know that.
  2. Static analysis tools (PHPStan, Psalm) and IDEs understand that code after fail(...) inside the if is unreachable. They therefore know that $quantity is an int at the return statement — not int|false — and do not report a type error.
  3. If someone later changes fail() so that it returns in some case, PHP reports the broken promise immediately.

A never Function That Returns

<?php
function broken(): never
{
    echo "Doing something\n";
}

try {
    broken();
} catch (TypeError $e) {
    echo $e->getMessage() . "\n";
}

 

Output

Doing something
broken(): never-returning function must not implicitly return

 

Reaching the end of the function is a violation. An explicit return statement in a never function is rejected at compile time.

Typical never Functions

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

function abort(int $status, string $message = ''): never
{
    http_response_code($status);
    echo $message;
    exit;
}

function notImplemented(string $feature): never
{
    throw new LogicException("$feature is not implemented yet.");
}

 

Frameworks use the same idea: Laravel's abort() helper, for example, always throws an HTTP exception.


void vs never

voidnever
Function returns?Yes, without a valueNever
Allowed statementsreturn; or no returnNo return; must throw, exit, or loop forever
Code after the callContinuesUnreachable
Examplelog(), save(), send()redirect(), abort(), fail()

 

never can also be used when overriding a method: because it is a bottom type, a child class may narrow any return type to never (for example, a method that is not supported in a particular implementation and always throws).


Other Special Standalone Types

Since PHP 8.2, null, false, and true can be used as standalone types:

function alwaysTrue(): true
{
    return true;
}

 

These are rarely needed in application code but help describe existing APIs precisely, especially in subclasses that narrow a parent's bool return type.


Common Mistakes

Using mixed to Avoid Thinking About Types

Effect: No type safety; every caller must check types.

Fix: Use specific types or small unions where possible.

Writing ?mixed or mixed|null

Effect: Compile error.

Fix: Use mixed alone.

Bare return; in a mixed Function

Effect: Compile error.

Fix: return null;.

A never Function That Can Return

Effect: TypeError at runtime when the end of the function is reached.

Fix: Ensure every path throws, exits, or loops forever.

Using void for Functions That Always Throw

Effect: Tools cannot recognize that subsequent code is unreachable.

Fix: Declare never.


Best Practices

  • Use mixed only for genuinely generic code, and narrow the type as soon as possible.
  • Declare mixed explicitly instead of omitting types, so intent is clear.
  • Use never for helpers that always throw or exit, such as fail(), abort(), and redirect().
  • Let static analysis tools benefit from never to understand control flow.
  • Prefer void for functions that simply return nothing.

Official reference: https\://www.php.net/manual/en/language.types.declarations.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer
Ask about this post
AI Ask about this post

Ask questions about Mixed and Never Types and get answers drawn from it.

Signed-in readers only.