Управление кодами возврата в PHP скриптах

Раздел: PHP основы -> Управление выполнением

Основные принципы и варианты использования кодов завершения

При завершении работы PHP-скрипта в командной строке (CLI) операционная система получает код возврата (exit code). Это целое число от 0 до 255, где 0 означает успешное выполнение, а любое ненулевое значение - ошибку или особое состояние. Управление кодом завершения позволяет интегрировать PHP-скрипты в системы автоматизации, конвейеры и скриптовые оболочки.

Основной способ: exit(целое_число)

Наиболее прямой способ задать код завершения - использовать конструкцию exit(целое_число) или die(целое_число). Обе функции эквивалентны.

<?php
if ($error) {
    exit(1); // завершение с кодом 1 (общая ошибка)
}
echo "Успех";
exit(0); // код 0
?>

Exit code php (коды завершения скрипта php)

В CLI сценарии этот код будет передан оболочке. Для проверки можно запустить скрипт и выполнить echo $? в bash. Важно: если передать строку, например exit('Ошибка'), то строка будет выведена, а код завершения станет 0, что может ввести в заблуждение. Рекомендуется всегда передавать целое число.

Типичные проблемы:

  • Вызов exit() без аргументов даёт код 0, даже если произошла ошибка.
  • Передача числа с плавающей точкой: exit(1.5) преобразуется в exit(1).
  • При передаче строки код всегда 0, а строка выводится в стандартный вывод, что может нарушить логику вызывающей программы.

Как завершить скрипт с кодом ошибки с помощью die()?

die() является синонимом exit(). Использование: die(2);. Отличий нет, но die традиционно ассоциируется с выводом сообщения. Если передать строку, она будет выведена перед завершением, а код станет 0. Поэтому для установки кода ошибки лучше использовать die(1);.

<?php
if (!file_exists('data.txt')) {
    die(2); // код 2 - файл не найден
}
?>

Проблема: в некоторых версиях PHP die() без аргумента ведёт себя как exit() и возвращает 0. Рекомендуется всегда явно указывать код.

Как получить код завершения от подключенного файла через return?

При выполнении include файл может вернуть значение через return. Если файл возвращает целое число, оно становится кодом завершения для текущего скрипта. Пример: файл config.php содержит return 2;. Тогда include 'config.php'; эквивалентно exit(2). Это удобно для модульных проверок.

<?php
// config.php
if (!defined('DB_HOST')) {
    return 10; // код 10 - ошибка конфигурации
}
return 0;
?>

// main.php
$exitCode = include 'config.php';
exit($exitCode);
?>

Если подключаемый файл не содержит return, include возвращает 1. Не путайте с функцией return внутри скрипта - она завершает только текущий файл, а не весь процесс.

Как гарантированно установить код завершения при фатальной ошибке?

Функция register_shutdown_function регистрирует callback, который выполняется при завершении скрипта (в том числе при фатальных ошибках). Внутри callback можно вызвать exit(код). Однако при фатальных ошибках стандартный обработчик может переопределить код. Решение: проверить error_get_last() и изменить код.

<?php
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error !== null && $error['type'] === E_ERROR) {
        exit(255); // фатальная ошибка -> код 255
    }
});
// некоторый код, который может вызвать ошибку
?>

Если в shutdown-функции не вызывать exit, код завершения остаётся тем, который был установлен ранее. При фатальных ошибках PHP автоматически устанавливает код 255, но его можно изменить.

Как связаны HTTP-код ответа и код завершения в CLI?

Для веб-среды HTTP-код ответа (например, 404) не связан с кодом завершения скрипта. В CLI функция http_response_code() не оказывает влияния на exit code. Не путайте эти понятия. Код завершения предназначен только для взаимодействия с операционной системой.

Расширенные примеры работы с exit-кодами

Приведенные ниже примеры демонстрируют нестандартные и детальные сценарии использования кодов завершения в PHP.

Пример 1. Проверка существования файла и возврат кода

Пример
<?php
function checkFile($path) {
    if (!file_exists($path)) {
        exit(1);
    }
    if (!is_readable($path)) {
        exit(2);
    }
    exit(0);
}
checkFile('data.txt');
?>
При отсутствии файла скрипт завершится с кодом 1. При наличии, но отсутствии прав чтения - с кодом 2. При успехе - 0.

Пример 2. Скрипт-калькулятор с кодами для разных типов ошибок

Пример
<?php
$a = $argv[1] ?? null;
$b = $argv[2] ?? null;
$op = $argv[3] ?? '+';
if ($a === null || $b === null) {
    exit(2); // недостаточно аргументов
}
if (!is_numeric($a) || !is_numeric($b)) {
    exit(3); // нечисловые аргументы
}
switch ($op) {
    case '+': echo $a + $b; break;
    case '/':
        if ($b == 0) exit(4); // деление на ноль
        echo $a / $b;
        break;
    default: exit(5); // неизвестная операция
}
exit(0);
?>
php calc.php 10 0 / → код 4, сообщение не выводится.

Пример 3. Использование register_shutdown_function для логирования и изменения кода

Пример
<?php
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error !== null) {
        file_put_contents('errors.log', date('Y-m-d H:i:s') . ' ' . $error['message'] . PHP_EOL, FILE_APPEND);
        if ($error['type'] === E_ERROR || $error['type'] === E_PARSE) {
            exit(255);
        }
    }
});
// принудительная ошибка
echo $undefinedVar;
?>
После выполнения в errors.log появится запись об ошибке, а скрипт завершится с кодом 255.

Пример 4. Интеграция с bash: проверка кода завершения

Пример
#!/bin/bash
php -r '
echo "Проверка связи\n";
exit(42);'
echo "Код завершения: $?"
Проверка связи
Код завершения: 42

В реальном скрипте можно использовать if php script.php; then ... fi для ветвления.

Пример 5. Комбинирование ошибок с помощью битовой маски

Пример
<?php
define('ERR_FILE', 1);   // 0001
define('ERR_DB',   2);   // 0010
define('ERR_NET',  4);   // 0100

$exitCode = 0;
if (!file_exists('config.php')) $exitCode |= ERR_FILE;
if (!db_connect()) $exitCode |= ERR_DB;
if (!network_check()) $exitCode |= ERR_NET;
exit($exitCode);
?>
Если произошла ошибка файла и сети, код будет 1+4=5. Вызывающая программа может проанализировать биты, чтобы понять, какие именно ошибки возникли.

Пример 6. Использование exit в дочернем процессе (pcntl_fork)

Пример
<?php
$pid = pcntl_fork();
if ($pid == -1) {
    exit(1); // ошибка fork
} elseif ($pid) {
    // родительский процесс
    pcntl_wait($status);
    $exitCode = pcntl_wexitstatus($status);
    echo "Дочерний процесс завершился с кодом: $exitCode\n";
} else {
    // дочерний процесс
    exit(7);
}
?>
Дочерний процесс завершился с кодом: 7

Этот подход позволяет создавать и контролировать параллельные задачи.

Коды завершения скрипта PHP - comments

En
Exit code php (php)