Что означает ошибка TypeError: Argument must be of type string, null given
Ошибка вида TypeError: Argument #1 must be of type string, null given возникает, когда функция или метод объявлены с параметром типа string, но фактически получают значение null. Это не проблема самой строки и не «сбой PHP»: интерпретатор сообщает о нарушении контракта типов. Практическая задача состоит не в том, чтобы скрыть исключение, а в том, чтобы найти место, где обязательное строковое значение потерялось или не было задано.
Типичный пример:
function normalizeEmail(string $email): string
{
return strtolower(trim($email));
}
$email = $_POST['email'] ?? null;
$result = normalizeEmail($email);
Если поле email отсутствует в запросе, переменная получит null, а вызов завершится TypeError до выполнения тела функции.
Как читать сообщение об ошибке
В полном сообщении обычно указаны имя функции, номер аргумента, ожидаемый и фактический типы, файл и строка вызова. Диагностику лучше начинать именно со строки вызова, а не со строки объявления метода.
| Фрагмент сообщения | Что он показывает |
|---|---|
| Argument #1 | Проблема в первом переданном аргументе |
| must be of type string | Сигнатура требует строку |
| null given | Во время выполнения передан null |
| called in ... on line ... | Место, где сформирован ошибочный вызов |
Если исключение прошло через несколько уровней приложения, изучите stack trace сверху вниз до первого файла вашего проекта. Фреймы фреймворка или библиотеки часто только передают управление, а источник некорректного значения находится в контроллере, сервисе, обработчике формы или репозитории.
Пошаговая диагностика
1. Проверьте значение непосредственно перед вызовом
Временно зафиксируйте тип и значение переменной. В рабочем приложении безопаснее писать диагностические данные в журнал, не выводя их посетителю.
error_log('email type: ' . get_debug_type($email));
error_log('email is null: ' . ($email === null ? 'yes' : 'no'));
$result = normalizeEmail($email);
Не записывайте в лог пароли, токены, полные платёжные данные и другие секреты. Для пользовательских полей часто достаточно типа, признака пустого значения и идентификатора операции.
2. Найдите источник null
Значение null обычно появляется в одном из следующих мест:
- отсутствующий ключ массива или параметр HTTP-запроса;
- поле базы данных, в котором разрешён NULL;
- метод поиска, не нашедший запись;
- необязательное свойство объекта;
- результат декодирования или преобразования входных данных;
- переменная, присвоенная только в одной ветке условия.
Проверяйте не только последнюю строку. Например, оператор ?? null делает код короче, но не превращает отсутствующее значение в корректную строку.
3. Определите бизнес-смысл параметра
До исправления нужно решить, допускается ли отсутствие значения. От ответа зависит сигнатура и поведение программы:
- если строка обязательна, нужно валидировать данные и прекращать операцию с понятной ошибкой;
- если значение необязательно, параметр должен быть nullable и код обязан обработать
null; - если допустима пустая строка, её можно использовать как значение по умолчанию, но только когда это соответствует логике приложения.
Автоматическая замена любого null на '' часто маскирует ошибку данных. Для адреса электронной почты, пути к файлу, имени класса или идентификатора пустая строка обычно так же некорректна, как и null.
Практические способы исправления
Вариант 1. Обязательное поле: валидация до вызова
Для обязательного значения проверьте наличие и формат до передачи в типизированный метод.
$email = $_POST['email'] ?? null;
if (!is_string($email) || trim($email) === '') {
throw new InvalidArgumentException('Поле email обязательно');
}
$result = normalizeEmail($email);
Такой код сохраняет строгую сигнатуру и выдаёт ошибку на понятном уровне приложения. В веб-форме исключение обычно заменяют добавлением ошибки валидации и возвратом формы пользователю.
Вариант 2. Необязательное поле: nullable-тип
Когда отсутствие значения допустимо, это следует отразить в контракте метода.
function normalizeMiddleName(?string $name): ?string
{
if ($name === null) {
return null;
}
$name = trim($name);
return $name === '' ? null : $name;
}
Nullable-сигнатура не отменяет обработку. Она только разрешает передать null; дальнейшее поведение нужно определить явно.
Вариант 3. Значение по умолчанию
Значение по умолчанию уместно для необязательных настроек и подписей. Перед подстановкой убедитесь, что пустая строка не меняет смысл операции и не превращает исходную проблему в другую ошибку.
Вариант 4. Исправление данных из базы
Если nullable-колонка фактически должна быть обязательной, исправьте не только PHP-код, но и данные. Сначала найдите строки с NULL, определите корректное значение, обновите записи, а затем ужесточите ограничение схемы. Не назначайте NOT NULL до очистки существующих данных.
SELECT id, email
FROM users
WHERE email IS NULL;
После миграции приложение всё равно должно валидировать входные данные: ограничение базы защищает хранилище, но не заменяет понятную обработку ошибок.
Ошибки при работе с массивами и JSON
Отсутствующий ключ массива
Проверка через isset() возвращает false и для отсутствующего ключа, и для ключа со значением null. Если эти ситуации различаются по смыслу, используйте array_key_exists().
$payload = ['name' => null];
var_dump(isset($payload['name'])); // false
var_dump(array_key_exists('name', $payload)); // true
Некорректный JSON
После декодирования входного JSON проверяйте ошибку и структуру результата до чтения полей.
try {
$data = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new InvalidArgumentException('Некорректный JSON', 0, $e);
}
if (!is_array($data)) {
throw new InvalidArgumentException('Ожидался JSON-объект');
}
$name = $data['name'] ?? null;
if (!is_string($name) || trim($name) === '') {
throw new InvalidArgumentException('Поле name обязательно');
}
Почему приведение типа не всегда решает проблему
Конструкция (string) $value преобразует null в пустую строку. TypeError исчезнет, но данные могут остаться неверными.
$email = (string) ($_POST['email'] ?? null);
$result = normalizeEmail($email);
Этот вариант допустим только тогда, когда пустая строка является официально разрешённым результатом. Для обязательных полей лучше оставить строгую проверку. Также не следует подавлять ошибки оператором @: он не восстанавливает потерянные данные и делает диагностику менее прозрачной.
Проверка исправления
После изменения кода проверьте не только успешный сценарий. Минимальный набор тестов должен включать:
- корректную непустую строку;
- отсутствующее поле;
- явное значение null;
- пустую строку и строку из пробелов;
- значение другого типа, например массив или число;
- запись из базы с NULL, если источник данных допускает его.
Краткий чек-лист
- откройте файл и строку вызова из stack trace;
- проверьте фактический тип аргумента через
get_debug_type(); - проследите источник значения до запроса, базы или метода поиска;
- решите, является ли параметр обязательным, nullable или имеющим значение по умолчанию;
- не заменяйте
nullна пустую строку без проверки бизнес-логики; - добавьте валидацию на границе системы;
- согласуйте ограничения PHP-кода и схемы базы данных;
- проверьте отсутствующее поле, null, пустую строку и неверный тип;
- удалите временную диагностику или оставьте только безопасное журналирование.
Надёжное исправление TypeError сохраняет строгий контракт метода и устраняет источник некорректного значения. После этого ошибка либо превращается в контролируемую валидацию, либо корректно поддерживается nullable-логикой, а не скрывается случайным приведением типа.