Проверка PHP кода на предмет ошибок: комплексный подход

Раздел: Разработка на PHP -> Проверка кода PHP

Основной подход: настройка отображения и логирования ошибок

Наиболее эффективный способ выявления ошибок в PHP коде - корректная конфигурация директив error_reporting, display_errors и error_log. Это позволяет видеть все ошибки непосредственно в процессе разработки и сохранять их для последующего анализа.

Для локальной среды разработки в файле php.ini или непосредственно в скрипте устанавливаются следующие параметры:

error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
ini_set('log_errors', '1');
ini_set('error_log', '/path/to/php_errors.log');

проверка php кода на ошибки (проверка php кода на ошибки)

Пояснения шагов:

  • error_reporting(E_ALL) - включает вывод всех типов ошибок, включая уведомления (notices) и предупреждения (warnings).
  • display_errors - разрешает вывод ошибок на экран. На продакшене эту директиву отключают из соображений безопасности.
  • display_startup_errors - аналогично, но для ошибок, возникающих при старте интерпретатора.
  • log_errors - включает запись ошибок в файл.
  • error_log - путь к файлу лога.
Типичная ошибка: на «боевом» сервере оставляют включённым display_errors, что может раскрыть чувствительную информацию. Решение - использовать условную логику:
if (in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
    ini_set('display_errors', '1');
} else {
    ini_set('display_errors', '0');
}

Как перехватывать и обрабатывать ошибки в коде?

Для гибкой обработки ошибок применяется пользовательский обработчик через set_error_handler().

function customErrorHandler($severity, $message, $file, $line) {
    if (!(error_reporting() & $severity)) {
        return;
    }
    throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('customErrorHandler');
try {
    // Код, который может вызвать ошибку
    $a = 1 / 0;
} catch (ErrorException $e) {
    echo 'Перехвачена ошибка: ' . $e->getMessage();
}

Пояснение: обработчик преобразует ошибки PHP в исключения ErrorException, что позволяет использовать блоки try/catch. Это удобно для централизованной логики обработки.

Проблема: обработчик не реагирует на фатальные ошибки (E_ERROR, E_PARSE). Для их перехвата используется register_shutdown_function и error_get_last(). Решение:
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        // Обработка фатальной ошибки
        echo 'Фатальная ошибка: ' . $error['message'];
    }
});

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

Инструменты статического анализа (PHPStan, Psalm) проверяют код на типовые ошибки без его запуска.

# Установка PHPStan через Composer
composer require --dev phpstan/phpstan
# Запуск анализа
vendor/bin/phpstan analyse src --level=max

Пояснение: PHPStan анализирует сигнатуры функций, типы переменных и выявляет потенциальные несоответствия. Уровень (level) от 0 до max определяет строгость проверок.

Распространённая ошибка: отсутствие файла конфигурации phpstan.neon, из-за чего анализ может не учитывать автозагрузку. Решение: создать конфиг с указанием путей к автозагрузчику.

Как получать подсказки об ошибках во время написания кода в IDE?

Современные IDE (PhpStorm, VS Code с расширениями) осуществляют синтаксический и семантический анализ в реальном времени.

Настройка PhpStorm: включить «Inspections» для PHP, указать уровень языка, пути к библиотекам. IDE выделяет ошибки (красным) и предупреждения (жёлтым).

// Пример, который PhpStorm подсветит как ошибку
function sum(int $a, int $b): int {
    return $a . $b; // Ожидается int, но возвращается string
}

Пояснение: анализатор IDE видит несоответствие типа возвращаемого значения и подсказывает исправление.

Проблема: если проект использует магические методы (__get, __call) или динамические типы, IDE может выдавать ложные срабатывания. Решение - добавить phpdoc-аннотации или конфигурационные файлы (например, .phpstorm.meta.php).

Как записывать ошибки для последующего анализа в production?

Использование error_log в сочетании с системой логирования (Monolog) позволяет сохранять ошибки в структурированном виде.

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$log = new Logger('app');
$log->pushHandler(new StreamHandler('/var/log/php/app.log', Logger::ERROR));

// Пример логирования
$log->error('Ошибка соединения с БД', ['db_host' => $host]);

Пояснение: Monolog поддерживает множество форматов, ротацию файлов, отправку email и интеграцию с внешними сервисами (Sentry, Logstash).

Типичная ошибка - не настроенная ротация логов, что приводит к переполнению диска. Решение: использовать RotatingFileHandler или утилиту logrotate.

Как автоматически проверять корректность функций с помощью юнит-тестов?

PHPUnit - стандартный фреймворк для модульного тестирования в PHP.

use PHPUnit\Framework\TestCase;

class MathTest extends TestCase {
    public function testAddition() {
        $this->assertEquals(4, 2 + 2);
    }
    public function testDivisionByZero() {
        $this->expectException(\DivisionByZeroError::class);
        1 / 0;
    }
}

Пояснение: тесты запускаются командой vendor/bin/phpunit. Тестирование покрывает ожидаемое поведение и выявляет регрессии.

Ошибка: тесты могут быть нестабильными из-за зависимости от внешних ресурсов (БД, API). Решение - использовать mock-объекты и контейнеры для изоляции.

Пример 1. Команда для синтаксической проверки файла (без выполнения):

Пример
php -l index.php

Пример вывода (без ошибок):

No syntax errors detected in index.php

Пример вывода (с ошибкой):

Parse error: syntax error, unexpected ';' in index.php on line 5

Пример 2. Настройка Xdebug для трассировки вызовов:

Пример
zend_extension=xdebug.so
xdebug.mode=develop,trace
xdebug.trace_output_dir=/tmp

После этого в файл trace.xt будет записана последовательность вызовов функций, что помогает найти логические ошибки.


Пример 3. Статический анализ с PHPStan уровня max с кастомными правилами:

Пример
// phpstan.neon
parameters:
    level: max
    paths:
        - src
    autoload_files:
        - vendor/autoload.php
    checkMissingIterableValueType: true
    checkGenericClassInNonGenericObjectType: false

Вывод PHPStan:

 ------ ----------------------------------------------------------------- 
  Line   src/Service/Calculator.php                                           
 ------ ----------------------------------------------------------------- 
  34     Method Calculator::divide() has parameter $b with no type hint. 
 ------ ----------------------------------------------------------------- 
 [ERROR] Found 1 error

Пример 4. Создание обработчика всех видов ошибок (включая фатальные) с записью в JSON-лог:

Пример
set_error_handler(function($severity, $message, $file, $line) {
    $data = [
        'type'    => $severity,
        'message' => $message,
        'file'    => $file,
        'line'    => $line,
        'time'    => date('Y-m-d H:i:s')
    ];
    file_put_contents('/tmp/errors.json', json_encode($data) . PHP_EOL, FILE_APPEND);
});
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE])) {
        $data = [
            'type'    => $error['type'],
            'message' => $error['message'],
            'file'    => $error['file'],
            'line'    => $error['line'],
            'time'    => date('Y-m-d H:i:s'),
            'fatal'   => true
        ];
        file_put_contents('/tmp/errors.json', json_encode($data) . PHP_EOL, FILE_APPEND);
    }
});
// Провокация ошибок
echo $undefinedVariable;
trigger_error('Пользовательское уведомление', E_USER_NOTICE);
functionThatDoesNotExist();

Содержимое файла errors.json после выполнения:

{"type":8,"message":"Undefined variable: undefinedVariable","file":"/test.php","line":20,"time":"2025-04-01 12:00:00"}
{"type":1024,"message":"Пользовательское уведомление","file":"/test.php","line":21,"time":"2025-04-01 12:00:00"}
{"type":1,"message":"Call to undefined function functionThatDoesNotExist()","file":"/test.php","line":22,"time":"2025-04-01 12:00:01","fatal":true}

Пример 5. Интеграция PHPStan с CI (GitHub Actions) для автоматической проверки при каждом коммите:

Пример
# .github/workflows/phpstan.yml
name: PHPStan
on: [push]
jobs:
  phpstan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - run: composer install --no-progress
      - run: vendor/bin/phpstan analyse --level=max

Результат: при наличии ошибок workflow прерывается, и разработчик видит отчёт.

Проверка PHP кода на ошибки - comments

En
проверка php кода на ошибки (php)