Типы возврата в PHP: от void до never
Введение в типы возвращаемых значений PHP
Типы возвращаемых значений (return type declarations) позволяют явно указать, какой тип данных должна вернуть функция или метод. Это повышает читаемость кода, помогает статическому анализу и предотвращает ошибки времени выполнения.
Основное решение - объявление типа возврата после двоеточия в сигнатуре функции.
function sum(int $a, int $b): int {
return $a + $b;
}
echo sum(2, 3); // 5Php 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)); // NULLPhp 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'); // abcPhp 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); // 123Php 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;
} // abcPhp 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); // 1212
Можно передавать такие функции как 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 гарантирует, что после вызова функции выполнение не продолжается.