Типы возврата в PHP: от void до never

Раздел: Основы программирования на PHP -> Типы данных в PHP

Введение в типы возвращаемых значений PHP

Типы возвращаемых значений (return type declarations) позволяют явно указать, какой тип данных должна вернуть функция или метод. Это повышает читаемость кода, помогает статическому анализу и предотвращает ошибки времени выполнения.

Основное решение - объявление типа возврата после двоеточия в сигнатуре функции.

function sum(int $a, int $b): int {
    return $a + $b;
}
echo sum(2, 3); // 5

Php mime type (mime-типы в php)

5

Of type string is deprecated php (предупреждение об устаревании типа string в php)

Начиная с PHP 7.0 можно указывать скалярные типы (int, float, string, bool), массивы (array), имена классов, интерфейсов. С PHP 7.1 добавлен void, с PHP 8.0 - union types и mixed, с PHP 8.1 - never и true/false как самостоятельные типы.

Типичная ошибка

Попытка вернуть значение неправильного типа вызывает TypeError. Например, если объявлен : int, а функция возвращает строку, PHP выбросит исключение. Для включения строгой проверки типов добавляют declare(strict_types=1); в начале файла.

Как сделать так, чтобы функция ничего не возвращала?

Используйте тип void (PHP 7.1+). Функция с : void не должна содержать return с выражением; допустим только пустой return; или отсутствие возврата.

function logMessage(string $msg): void {
    echo '[' . date('H:i:s') . '] ' . $msg . PHP_EOL;
}
logMessage('Тест');

Php check type (проверка типа переменной в php)

[14:30:00] Тест

Strict type php (строгая типизация в php)

Проблема

Попытка вернуть значение из функции с : void приведет к фатальной ошибке: Fatal error: A void function must not return a value.

Как разрешить возврат NULL для любого типа?

Добавьте вопросительный знак перед типом (nullable type, PHP 7.1+). Это означает, что функция может вернуть либо указанный тип, либо null.

function findUser(int $id): ?array {
    $users = [1 => 'Alice', 2 => 'Bob'];
    return isset($users[$id]) ? [$id => $users[$id]] : null;
}
var_dump(findUser(1)); // array(1) { [1]=> string(5) "Alice" }
var_dump(findUser(3)); // NULL

Php type int (тип int в php)

Типичная ошибка

Забывают, что ?type отличается от type|null в union-типах только синтаксически, но результат одинаков.

Как объявить, что функция возвращает значение одного из нескольких типов?

Используйте union types (PHP 8.0+). Список типов через вертикальную черту. Например, int|string, array|false.

function parseId(string $input): int|string {
    if (is_numeric($input)) {
        return (int) $input;
    }
    return $input;
}
echo parseId('42'); // 42
echo parseId('abc'); // abc

Php return types (типы возвращаемых значений в php)

Важное замечание

Тип mixed эквивалентен union всех возможных типов, но его использование не рекомендуется, когда точность типов важна. false и null можно указывать отдельно, например string|false.

Как указать, что возвращаемое значение может быть любого типа?

Тип mixed (PHP 8.0+). Это эквивалент object|resource|array|string|int|float|bool|null.

function identity(mixed $value): mixed {
    return $value;
}
echo identity(123); // 123

Php 7 types (типы данных в php 7)

Недостаток

Чрезмерное использование mixed сводит на нет преимущества строгой типизации. Лучше использовать union types с конкретными вариантами.

Как вернуть объект того же класса, в котором объявлена функция?

Для возврата экземпляра текущего класса используйте self, для возврата экземпляра класса-потомка - static (PHP 8.0+), для родительского - parent.

class ParentClass {
    public function create(): self {
        return new self();
    }
}
class ChildClass extends ParentClass {
    public function create(): static {
        return new static();
    }
}
var_dump((new ChildClass())->create()); // object(ChildClass)

Php set type (функция settype() в php)

Разница между self и static

self всегда ссылается на класс, где написан код, а static – на класс, в котором метод вызван (позднее статическое связывание). Использование static с возвращаемым типом требует PHP 8.0+.

Как указать, что функция возвращает итератор или массив для перебора?

Тип iterable (PHP 7.1+). Принимает как array, так и объекты, реализующие Traversable.

function getItems(): iterable {
    return ['a', 'b', 'c'];
}
foreach (getItems() as $item) {
    echo $item;
} // abc

Php number type (числовые типы в php)

Ограничение

Тип iterable не позволяет вызывать на возвращенном значении методы, специфичные для массива или объекта Iterator, без дополнительной проверки.

Как объявить, что функция никогда не завершается нормально?

Тип never (PHP 8.1+). Используется для функций, которые всегда выбрасывают исключение, вызывают exit(), die() или бесконечный цикл.

function abort(string $reason): never {
    throw new Exception($reason);
}
// или
function redirect(string $url): never {
    header('Location: ' . $url);
    exit;
}

Важно

Функция с never не должна иметь return, даже без значения. Попытка вернуть значение вызовет ошибку.

Расширенные примеры использования return types

Ковариантность и контравариантность (PHP 7.4+)

В PHP 7.4 появилась возможность ковариантности возвращаемого типа в классах-потомках (т.е. возвращать более конкретный тип). Контравариантность аргументов добавлена в PHP 7.4.

Пример
interface Animal {}
class Dog implements Animal {}
class Cat implements Animal {}
class PetOwner {
    public function adopt(): Animal {
        return new Cat();
    }
}
class DogOwner extends PetOwner {
    // Ковариантность: возвращаем более конкретный тип
    public function adopt(): Dog {
        return new Dog();
    }
}
$owner = new DogOwner();
var_dump($owner->adopt()); // object(Dog)
object(Dog)#2 (0) { }

Ошибка при нарушении ковариантности

Если потомок попытается вернуть менее конкретный тип (например object вместо Dog), PHP выдаст фатальную ошибку.

Типы возврата в анонимных функциях и замыканиях

Анонимные функции также поддерживают return types.

Пример
$multiply = function(int $x, int $y): int {
    return $x * $y;
};
echo $multiply(3, 4); // 12
12

Можно передавать такие функции как callable и сохранять сигнатуру.

Использование return types с интерфейсами и абстрактными классами

В интерфейсах можно объявлять типы возврата для методов, которые должны быть реализованы.

Пример
interface HasName {
    public function getName(): string;
}
class User implements HasName {
    private string $name;
    public function __construct(string $name) {
        $this->name = $name;
    }
    public function getName(): string {
        return $this->name;
    }
}
echo (new User('Анна'))->getName(); // Анна
Анна

Дженерики через docblock и static анализ (не встроенные в PHP)

Хотя PHP не имеет встроенных дженериков, можно использовать return types в сочетании с аннотациями PHPDoc для статического анализа (например, PhpStan).

Пример
/**
 * @template T
 * @param T $value
 * @return T
 */
function wrap(mixed $value): mixed {
    return $value;
}
// В рантайме тип mixed, но PhpStan поймет, что возвращается int для wrap(123)

На практике return type mixed не даёт строгости, поэтому лучше перегружать функции утиной типизацией или использовать union types с конкретными типами.

Возвращение callable с помощью типа callable

Тип callable может быть указан как возвращаемый, хотя это редко используется.

Пример
function getLogger(string $prefix): callable {
    return function(string $msg) use ($prefix) {
        echo "[$prefix] $msg";
    };
}
$logger = getLogger('APP');
$logger('Запуск'); // [APP] Запуск
[APP] Запуск

Ограничение callable в возврате

Тип callable не проверяется на количество и типы аргументов, что может привести к ошибкам времени выполнения.

Пример с never: функция, которая выбрасывает исключение

Пример
function assertNotNull(?string $value): never {
    if ($value === null) {
        throw new InvalidArgumentException('Значение не может быть null');
    }
    // Функция не доходит до этой точки, иначе нарушает never
}
// assertNotNull(null); // вызовет исключение

Тип never гарантирует, что после вызова функции выполнение не продолжается.

Типы возвращаемых значений в PHP - comments

En
Php return types (php)