Что означает «версия PHP»
Версия PHP — это не просто строка из php -v. В реальном проекте она задаёт доступный синтаксис, набор стандартных функций, поведение расширений, совместимость Composer-пакетов и окно security-фиксов. Код на PHP 8.4 может использовать возможности, которых нет в 8.1; пакет может требовать php: ^8.3; контейнер может запускать CLI 8.4, а веб-сервер — FPM 8.2. Поэтому версию всегда проверяют там, где код реально выполняется.
На 15 июня 2026 года официально поддерживаются ветки 8.2, 8.3, 8.4 и 8.5. PHP 8.2 и 8.3 уже находятся в режиме security fixes only; PHP 8.4 и 8.5 ещё получают active support. После EOL ветка больше не получает исправлений от проекта PHP, и это уже не вопрос вкуса: сервис остаётся с известными уязвимостями, даже если «всё работает». Подробная тема обновлений вынесена в Миграции между версиями PHP.
php -v
php --ini
php -i | grep "Server API"
php -r 'echo PHP_VERSION, "\n", PHP_VERSION_ID, "\n", PHP_SAPI, "\n";'PHP_VERSION_ID удобен для машинных проверок: например, PHP 8.4.x кодируется как число вида 80400+. Это лучше, чем парсить строку версии вручную.
SAPI: как PHP подключён к внешнему миру
SAPI — Server API, слой между Zend Engine и окружением, которое запускает PHP. Один и тот же файл может выполняться через разные SAPI и вести себя по-разному: в CLI есть $argv, в веб-запросе есть заголовки и суперглобалы, во встроенном сервере SAPI будет cli-server, в PHP-FPM — обычно fpm-fcgi.
flowchart TD
A[Окружение запуска] --> B{SAPI}
B --> C[CLI: команды, cron, миграции]
B --> D[cli-server: локальная разработка]
B --> E[PHP-FPM / FastCGI: веб-запросы]
B --> F[Apache module: apache2handler]
C --> G[Zend Engine выполняет PHP-код]
D --> G
E --> G
F --> G
H[php.ini и расширения] --> G
G --> I[Результат: stdout, HTTP-ответ, exit code, логи]Практически важные варианты:
cli— запуск из терминала: миграции, cron, консольные команды, скрипты обслуживания. Подробнее см. CLI и встроенный сервер.cli-server— встроенный dev-серверphp -S. Полезен локально, но не предназначен для production.fpm-fcgi— PHP-FPM через FastCGI, типичная связка с nginx или Apache. Смежная тема: PHP-FPM, RoadRunner и долгоживущие воркеры.cgi-fcgi— CGI/FastCGI-варианты; в современных деплоях чаще встречается именно FPM.apache2handler— PHP как модуль Apache.phpdbg— отладочный SAPI для запуска и анализа кода.
Минимальная диагностика внутри скрипта:
<?php
printf("PHP: %s (%d)\n", PHP_VERSION, PHP_VERSION_ID);
printf("SAPI: %s\n", PHP_SAPI);
printf("Loaded php.ini: %s\n", php_ini_loaded_file() ?: 'none');Не стоит строить бизнес-логику вокруг SAPI без нужды, но для загрузки bootstrap-файлов, выбора формата логов или запрета веб-запуска консольного скрипта это нормальная проверка.
php.ini и разные конфиги для разных режимов
php.ini — основной конфигурационный файл интерпретатора. В нём включают расширения, задают memory_limit, upload_max_filesize, error_reporting, display_errors, date.timezone, opcache.* и десятки других директив. При этом «один PHP» не означает «один php.ini»: CLI и FPM часто читают разные конфиги.
Проверяйте так:
php --ini
php -i | grep "Loaded Configuration File"А для FPM — через phpinfo() в временном закрытом endpoint, через логи запуска FPM или через конфигурацию образа/пакета. В production phpinfo() нельзя оставлять публично: он раскрывает пути, расширения и настройки окружения.
Важная деталь: php.ini читается при старте PHP. Для CLI это каждый запуск команды. Для веб-рантаймов с долгоживущими процессами после изменения конфига обычно нужен reload/restart соответствующего сервиса: php-fpm, Apache, контейнера или supervisor-процесса. Это особенно важно для opcache, лимитов памяти и включения расширений.
Некоторые директивы меняются не везде. У каждой настройки есть режим изменяемости: INI_ALL, INI_PERDIR, INI_SYSTEM и т. п. Например, часть параметров можно задать через ini_set() в коде, а часть — только на уровне системного конфига. Поэтому «поставлю ini_set() в bootstrap» не является универсальным решением.
CLI, FPM, CGI и встроенный сервер: один язык, разные сценарии
CLI-скрипт живёт в процессе команды: стартовал, выполнил код, завершился. Это удобно для задач, где состояние не должно переживать запуск. Веб-запрос через FPM обычно обслуживается worker-процессом, который переживает множество запросов. Суперглобалы вроде $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES раскрываются подробно в SAPI и суперглобалы, но уже здесь важно помнить: их смысл зависит от режима выполнения.
Встроенный сервер запускается так:
php -S localhost:8000 -t publicОн удобен для локального просмотра простых приложений и примеров, но не заменяет nginx/Apache/FPM в production. Официальная документация прямо предупреждает, что built-in server предназначен для разработки. Если нужно понять production-модель с пулами воркеров, keep-alive, перезапусками и утечками состояния, это уже область PHP-FPM, RoadRunner и долгоживущие воркеры.
Почему lifecycle влияет на код
Устаревшая ветка PHP бьёт по проекту в трёх местах. Первое — безопасность: после EOL нет официальных исправлений для новых уязвимостей. Второе — зависимости: библиотеки постепенно поднимают минимальную версию PHP, и composer update начинает конфликтовать с рантаймом. Третье — поддерживаемость: команда не может использовать новые типы, синтаксис и стандартные API без оглядки на старый production.
В Composer это часто фиксируют явно:
{
"require": {
"php": "^8.3"
},
"config": {
"platform": {
"php": "8.3.0"
}
}
}require.php говорит, на каких версиях пакет должен работать. config.platform.php заставляет Composer рассчитывать зависимости так, будто он работает на указанной версии, даже если локально у разработчика стоит более свежий PHP. Это полезно, но опасно как самообман: CI и production всё равно должны реально запускаться на заявленной версии.
Типичные ловушки
Самая частая ловушка — проверить php -v в терминале и решить, что веб-приложение работает на той же версии. На сервере это может быть CLI 8.4 и FPM 8.2. Вторая — поменять php.ini и забыть перезапустить долгоживущий runtime. Третья — считать minor-обновления «безопасными по определению»: PHP старается сохранять совместимость, но deprecations, изменения расширений и новые reserved words всё равно требуют прогонки тестов и чтения migration guide.
Ещё одна практичная привычка: в инцидентах логируйте не только версию приложения, но и PHP_VERSION, PHP_SAPI, путь к php.ini, список критичных расширений и режим opcache. Это резко сокращает время на вопросы вроде «почему в cron работает, а в вебе падает».
См. также
- Миграции между версиями PHP — как читать migration guides и планировать обновления.
- CLI и встроенный сервер — детали запуска из терминала и локального dev-сервера.
- PHP-FPM, RoadRunner и долгоживущие воркеры — production-модель процессов и состояние между запросами.
- SAPI и суперглобалы — как request data попадает в PHP.
- Конфигурация безопасности PHP — настройки, которые нельзя оставлять «как на локалке».