Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 4 · С нуля → диагностика

Конфигурация PHP: найти настройку, понять область и проверить результат

Активный php.ini и scan-ini, синтаксис и единицы, ini_set и режимы INI_*, CLI/FPM, ошибки разработки и сайта, .user.ini, .htaccess и условные секции.

Конфигурация: правила для запуска, а не исходный код

Наглядная модель

Одна машина — разные источники настроек

Сначала выбираем процесс, поведение которого проверяем. Путь к одному ini ещё не описывает весь результат.

  • Команда CLI

    Выбранный php.exe → его основной и дополнительные ini → параметры запуска → разрешённые изменения кода.

  • Запрос сайта

    Его веб-SAPI → собственные ini и настройки сервера/каталога → разрешённые изменения кода; admin-запреты сохраняются.

  • Проверяем в том же процессе

    PHP_SAPI и версия: кто работает. Загруженные ini: откуда настройки. ini_get: что действует сейчас.

Здесь сопоставлены контексты, а не задан универсальный порядок всех конфигурационных механизмов. .user.ini, .htaccess и FPM применяются при разных условиях.

PHP уже исполняет файл. Теперь нужно понять, почему локально видна ошибка, на сайте — пустой ответ, а изменение лимита будто игнорируется. Конфигурация задаёт правила для PHP: часовой пояс по умолчанию, показ ошибок, ограничения и загрузку расширений. Файл php.ini содержит такие правила в специальном текстовом формате.

Представьте рабочее место с листом настроек: какой исполнитель пришёл, тот и читает свой лист. CLI и веб-процесс могут читать разные листы. Аналогия ограничена: кроме главного файла есть дополнительные файлы, настройки SAPI, администратора и разрешённые временные изменения из программы.

ВопросНаблюдаемый ответ
Какой PHP выполняет работу?Путь запуска, версия, PHP_SAPI
Откуда пришли настройки?Основной ini, дополнительные ini, настройки выбранного SAPI
Что действует сейчас?ini_get нужной директивы в том же процессе
Можно ли изменить это здесь?Режим INI_* и ограничения администратора

Сначала прочитаем одну настройку, затем разберём её изменение. До работы с конфигурацией пройдите запуск конкретного PHP и hello.php. Для первых команд не нужны собственные функции, массивы или веб-сервер.

Найти действительно загруженный php.ini

Не выбирайте первый найденный поиском файл php.ini. На компьютере могут жить несколько версий PHP, шаблоны php.ini-development / php.ini-production и конфигурации отдельных SAPI. Файл шаблона не становится активным из-за наличия на диске.

Читаем состояние конкретного исполнителя
  1. Полный путь к php.exe
  2. --ini сообщает основной и дополнительные файлы
  3. В выбранном процессе читаем нужную директиву
PowerShell: версия, основной ini и дополнительные iniФрагмент или команда
& 'C:\Tools\PHP\php.exe' -v
& 'C:\Tools\PHP\php.exe' --ini

Предусловие: это подтверждённый путь к установленному PHP. В выводе --ini различайте Configuration File Path (каталог поиска), Loaded Configuration File (реально загруженный основной файл) и Additional .ini files parsed (дополнительные файлы). Пустой Loaded Configuration File или (none) не означает, что PHP неисправен. Конкретные пути зависят от установки.

Если основной файл отсутствует, PHP использует встроенные значения и применимые другие источники. Для собственного учебного окружения можно подготовить отдельный lesson.ini и выбрать его через -c, как ниже. Для рабочего сервера сначала установите владельца конфигурации и способ её применения.

Вопрос «какой php.ini используется?» встречается в этом обсуждении. Ответ должен содержать способ запуска: --ini описывает CLI, а не автоматически сайт.

Запустить учебный файл без iniФрагмент или команда
& 'C:\Tools\PHP\php.exe' -n 'C:\PhpLessons\charset.php'

Предусловие: charset.php содержит следующий самостоятельный пример. -n отключает загрузку php.ini и дополнительных ini для этого запуска, не удаляя файлы. Поэтому могут исчезнуть подключаемые расширения. Это контрольный опыт для CLI, а не способ исправить конфигурацию сайта.

charset.php: прочитать одну настройкуСамостоятельный пример
<?php
echo ini_get('default_charset'), "\n";
Ожидаемый результат
UTF-8

Ожидаемое значение относится к запуску PHP 8.2+ с -n, как в предыдущей команде. При обычном запуске настройка может быть переопределена. ini_get — готовая функция: ей передают имя директивы строкой, она возвращает текущее строковое значение либо false для неизвестной директивы. Это чтение, а не изменение кодировки исходного файла.

Имя default_charset заключено в кавычки, потому что передаётся как текст. Скобки означают вызов функции. echo выводит возвращённое значение и перевод строки. UTF-8 здесь ожидается благодаря явно указанному -n. Это проверка исходного состояния, после неё возвращайтесь к обычному запуску для диагностики своего окружения.

Синтаксис ini: имя, значение, комментарий и единица

Сохраните отдельный lesson.ini для учебных опытов. Каждая строка присваивает значение директиве. Имена здесь не придумывают: memory_limit и date.timezone уже определены PHP или расширением. PHP-код вроде echo в ini не выполняется.

ФрагментКак читать
имя = значениеОдна директива; пробелы вокруг = для удобства
; пояснениеКомментарий до конца строки
"UTC"Строковое значение в кавычках
On / OffВключено / выключено для логической директивы
128MРазмер с единицей, если данная директива поддерживает размеры
[PHP] или [Date]Обычная группировка для читателя; сама по себе не ограничивает действие настройкой модуля
Устройство учебного php.iniФрагмент или команда
; Только отдельная учебная конфигурация.
default_charset = "UTF-8"
date.timezone = "UTC"
memory_limit = 128M
display_errors = On
log_errors = Off

Это синтаксический пример настроек, не целиком готовый профиль рабочего сайта. Слева точное имя директивы, справа значение; знака $ и PHP-тега нет. ; начинает комментарий вне кавычек. UTC — часовой пояс, 128M — ограничение памяти PHP, On/Off — логические значения для соответствующих директив. Смысл и возможность изменения проверяют у каждой директивы отдельно.

Не переносите в ini способы экранирования из PHP-строк. Кавычки помогают сохранить текстовые значения с особыми символами; обратная косая черта здесь не работает как универсальное PHP-экранирование. Для Windows-путей в примерах используем прямые слеши. Не меняйте кодировку исходного файла, думая, что default_charset перекодирует уже существующие байты.

8M — размер в байтах, а не число 8Самостоятельный пример
<?php
echo ini_parse_quantity('8M'), "\n";
echo ini_parse_quantity('512K'), "\n";
Ожидаемый результат
8388608
524288

ini_parse_quantity существует с PHP 8.2. В синтаксисе размеров K, M, G используют множители 1024. Функция возвращает целое количество байтов; простое приведение строки "8M" к числу теряет единицу. Здесь только заранее корректные положительные значения. Специальное -1 имеет смысл лишь у тех директив, которые его разрешают; функция не решает эту семантику вместо документации.

Читать размер надо вместе с правилом конкретной директивы: memory_limit — ограничение выделяемой скриптом памяти PHP, а не объём всей оперативной памяти машины. Повышение лимита не ускоряет алгоритм автоматически. Причину роста расхода исследуют измерениями.

Основной файл, scan-ini и параметры одного запуска

При старте PHP ищет основной ini по правилам SAPI и платформы. Явный -c у CLI позволяет выбрать нужный файл. На поиск также влияют PHPRC, в Windows — документированные ключи реестра и пути, у сервера — его настройки. CLI не берёт php.ini из текущего рабочего каталога просто потому, что вы туда перешли.

Если в пути поиска имеется php-SAPI.ini, например php-cli.ini, он используется вместо php.ini для этого SAPI. После основного файла PHP может читать дополнительные .ini из каталога сканирования в алфавитном порядке. Поэтому значение в основном файле может не быть итоговым.

Пример изменения одной настройки
  1. lesson.ini: default_charset = UTF-8
  2. Запуск с -c выбирает этот основной файл; --ini показывает также scan-ini
  3. -d default_charset=ISO-8859-1 задаёт значение данному CLI-процессу
  4. charset.php читает текущее значение: ISO-8859-1
Выбрать отдельный учебный ini на один CLI-запускФрагмент или команда
& 'C:\Tools\PHP\php.exe' -c 'C:\PhpLessons\lesson.ini' --ini
& 'C:\Tools\PHP\php.exe' -c 'C:\PhpLessons\lesson.ini' -d default_charset=ISO-8859-1 'C:\PhpLessons\charset.php'

Предусловия: lesson.ini существует и содержит предыдущий фрагмент, charset.php — пример чтения. -c выбирает основной файл, -d задаёт одну директиву для этого процесса; ожидаемая строка второй команды — ISO-8859-1. Дополнительные scan-ini всё ещё могут участвовать в запуске с -c: проверяйте --ini. Команды не редактируют общий php.ini. -n и -c здесь не совмещаются.

PHP_INI_SCAN_DIR меняет каталоги сканирования для процесса; разделитель каталогов — ; на Windows и : на Unix. Пустой элемент списка может вернуть также каталог, заданный при сборке. Это причина внимательно читать полный вывод --ini, а не только Loaded Configuration File. В этой главе переменные системы и реестр не меняются.

Модуль PHP читает ini при запуске веб-сервера; CLI и CGI — при каждом запуске. После правки конфигурации долгоживущего сервиса нужен предусмотренный его окружением reload/restart и проверка новых процессов. Универсальная команда перезапуска всех серверов здесь была бы неверной.

Полный порядок поиска по платформам и реестру сохранён в официальном описании configuration.file; здесь освоен проверяемый выбор CLI-файла.

Почему CLI и сайт показывают разные значения

php --ini выполняет CLI. Запрос сайта обслуживает другой процесс, иногда другой версии, с другими модулями и каталогами настроек. Даже одинаковый путь к основному php.ini не доказывает равенства итоговых настроек: остаются scan-ini и уровни сервера. Это предмет обсуждения о расхождении php -i и phpinfo.

Нужно сравнитьCLIЗакрытая диагностика сайта
Версия и SAPIphp -v; PHP_SAPIPHP_VERSION и PHP_SAPI в обслуживающем процессе
Прочитанные файлыphp --iniphp_ini_loaded_file и php_ini_scanned_files
Нужная настройкаini_get в CLI-файлеini_get той же директивы при HTTP-запросе

Следующий код предполагает, что уже изучены переменная и присваивание и проверка условия. $loaded хранит результат чтения пути; === false отличает отсутствие основного ini от строки с путём. echo выводит plain text: HTML-разметка здесь не создаётся.

Локальная диагностика процесса, обслуживающего страницуПример для указанного окружения
<?php
header('Content-Type: text/plain; charset=UTF-8');
echo "SAPI: ", PHP_SAPI, "\n";
echo "Version: ", PHP_VERSION, "\n";
$loaded = php_ini_loaded_file();
if ($loaded === false) {
    echo "Main ini: none\n";
} else {
    echo "Main ini: ", $loaded, "\n";
}
echo "Additional ini: ", php_ini_scanned_files(), "\n";
echo "Charset: ", ini_get('default_charset'), "\n";

Полный PHP-файл для закрытой локальной диагностики. Предусловия: уже настроенный нужный веб-SAPI и доступ только разработчику. Вывод содержит фактическую версию, SAPI и пути, поэтому точный текст зависит от окружения. Здесь выполнен lint; FPM/Apache не запускались. После диагностики файл удаляют из доступного по HTTP каталога. Не публикуйте phpinfo или полный набор путей/настроек.

Не пытайтесь заставить CLI «стать FPM», передав ему случайный серверный ini. Это не меняет его SAPI, права, окружение и обработчик HTTP. Сначала проверьте настройку в том процессе, поведение которого исправляете.

ini_set: временная настройка и явная проверка отказа

Иногда одному действию нужна разрешённая временная настройка. ini_set получает два аргумента: точное имя директивы и новое значение. Он возвращает старое значение при успехе или false при отказе. Изменение относится к текущему выполнению; файл php.ini на диске не редактируется.

$before — переменная со старым значением; if выбирает ветвь по результату. Перед этой ступенью прочитайте присваивание и if. Здесь эти конструкции используются, чтобы отличить изменение от отказа и не выдавать желаемое за действительное.

Временная настройка не теряет прежнее значение
  1. ini_set получает имя и новую строку
  2. Если вернул false — сообщаем отказ
  3. При успехе читаем новое значение
  4. Возвращаем сохранённое старое значение
Изменить одну настройку и вернуть предыдущее значениеСамостоятельный пример
<?php
$before = ini_set('default_charset', 'ISO-8859-1');
if ($before === false) {
    echo "Настройка не изменена\n";
} else {
    echo "Временно: ", ini_get('default_charset'), "\n";
    ini_set('default_charset', $before);
    echo "Возврат: ", ini_get('default_charset'), "\n";
}
Ожидаемый результат
Временно: ISO-8859-1
Возврат: UTF-8

Проверяемый запуск с -n начинается с UTF-8. ini_set возвращает прежнюю строку либо false при отказе, поэтому сравнение строгое: === false. Нельзя путать отказ со старым значением "0". Здесь меняется только настройка процесса; сами байты исходника не перекодируются. В администраторски ограниченном окружении возможна ветвь отказа.

ini_restore возвращает значение из исходной конфигурации, а не обязательно то, которое установил внешний вызывающий код минуту назад. Для вложенной временной смены сохраняйте результат ini_set и восстанавливайте именно его. В долгоживущем CLI-процессе изменение способно затронуть следующие задания; завершение одной вашей функции не возвращает настройку автоматически.

Не подавляйте отказ через @. Проблема может быть в режиме директивы, неизвестном имени или запрете администратора. ini_get показывает принятое значение, но для некоторых настроек важны ещё ограничения и момент обработки запроса.

INI_USER, INI_PERDIR, INI_SYSTEM и INI_ALL

Режим изменения — разрешённый уровень настройки конкретной директивы. Это не пользователь Windows и не право редактирования файла. Если у вас есть доступ к php.ini, это ещё не значит, что любую настройку можно изменить из PHP-кода.

РежимГде предусмотрено изменениеПример
INI_USERВо время скрипта; также предусмотренные пользовательские механизмыУровень, включающий runtime-доступ
INI_PERDIRphp.ini и подходящие настройки каталога/сервера, .user.ini для CGI/FastCGIupload_max_filesize: не через ini_set
INI_SYSTEMphp.ini и системная конфигурация сервераallow_url_fopen: не через .user.ini или ini_set
INI_ALLВсе предусмотренные уровни, с учётом SAPI и admin-запретовdisplay_errors

php.ini может задавать директивы этих режимов. Для INI_USER официальный список дополнительно включает Windows registry; это отдельный платформенный механизм. INI_ALL не делает .htaccess рабочим в Nginx и не отменяет php_admin_value. Проверяйте и режим, и применимость механизма.

Почему изменение лимита не сработало
  1. Код вызывает ini_set("upload_max_filesize", "20M")
  2. Режим INI_PERDIR запрещает runtime-изменение
  3. Функция возвращает false → выбираем настройку до запроса
Убедиться, что лимит загрузки не меняется внутри скриптаСамостоятельный пример
<?php
$old = ini_set('upload_max_filesize', '20M');
if ($old === false) {
    echo "Нужна настройка до выполнения скрипта\n";
} else {
    echo "Настройка изменена\n";
}
Ожидаемый результат
Нужна настройка до выполнения скрипта

upload_max_filesize имеет режим INI_PERDIR. ini_set не вправе менять его во время выполнения — даже в CLI без загруженного php.ini. Для HTTP лимиты разбора запроса должны действовать ещё до начала вашего кода. Этот пример показывает отказ функции, а не испытывает настоящую загрузку файла.

Такая ошибка разбирается в вопросе про upload_max_filesize. Успешный вход в ваш скрипт ещё не означает, что PHP примет переопределение. Для загрузок согласуют также post_max_size и ограничения HTTP-сервера; подробности — начальный урок загрузки файлов.

Дополнительная ступень после массива с ключами: запросить метаданные директивы. Это помогает строить локальный диагностический отчёт, но не заменяет проверку фактического ini_set под администраторскими ограничениями.

Получить режим изменения конкретной директивыСамостоятельный пример
<?php
$settings = ini_get_all(null, true);
$access = $settings['upload_max_filesize']['access'];
echo "Доступ из кода: ", ($access & INI_USER) ? 'да' : 'нет', "\n";
echo "Доступ уровня каталога: ", ($access & INI_PERDIR) ? 'да' : 'нет', "\n";
Ожидаемый результат
Доступ из кода: нет
Доступ уровня каталога: да

Поздняя диагностическая ступень после массивов: null выбирает все расширения, true просит подробности; две пары [] берут сведения сначала о директиве, затем о поле access. ini_get_all также возвращает global_value и local_value. access — числовая маска нескольких разрешённых уровней, а не само значение лимита. Оператор & проверяет присутствие флага; ненулевой результат выбирает «да» через условие ? : . Сравнивать всю маску на точное равенство INI_PERDIR нельзя: в ней может одновременно присутствовать INI_SYSTEM. Весь массив в браузер не выводится.

Разработка и рабочий сайт: куда попадают ошибки

У настройки ошибок три разных вопроса. error_reporting выбирает диагностические уровни. display_errors разрешает отправлять диагностику в вывод. log_errors включает запись в журнал. Пользователю сайта нужен понятный ответ; автору — технические сведения в контролируемом месте.

php.ini-development и php.ini-production — поставляемые шаблоны с разными намерениями, а не доказательство действующих настроек. Встроенные значения без ini могут отличаться от обоих шаблонов. Выберите свой файл сознательно и проверьте итог в нужном SAPI.

ОкружениеОжидаемое поведение при диагностикеЧто ещё проверить
Изолированная разработкаАвтор видит техническое сообщениеВ ответе могут появиться пути и детали; доступ только автору
Рабочий сайтПосетитель не получает внутреннюю диагностикуЖурнал реально пишется, защищён и не растёт без ограничения
Учебная локальная конфигурация показа ошибокФрагмент или команда
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = Off

Фрагмент для изолированного локального опыта. E_ALL — именованная маска уровней ошибок, поддерживаемая синтаксисом php.ini. Вывод ошибок удобен автору, но не подходит публичному ответу. Здесь логирование выключено лишь для этого короткого локального опыта; для длительной разработки можно включить его и назначить отдельный журнал.

Направление политики для рабочего сайта: ответ без диагностикиФрагмент или команда
error_reporting = E_ALL
display_errors = Off
display_startup_errors = Off
log_errors = On

Это фрагмент политики, не полный production php.ini. До применения администратор настраивает действующий журнал, права записи, доступ, ротацию и проверяет запись тестового сообщения в своём окружении. Конкретный error_log зависит от сервера. Отключение display_errors не исправляет ошибку и само по себе не гарантирует, что журнал существует.

ini_set("display_errors", "1") внутри файла не покажет синтаксическую ошибку, из-за которой этот же файл вообще не начал выполняться. Ошибки запуска PHP также возникают до ваших инструкций. Поэтому настраивать диагностику для таких случаев нужно до выполнения: через действующую конфигурацию или параметры контролируемого CLI-запуска.

Подавление вывода не создаёт правильный HTTP-код и пользовательскую страницу ошибки. Это работа приложения и сервера, описанная в разборе диагностики и исключений. Наличие log_errors=On не подтверждает успешную запись: важны путь, права и выбранный обработчик журнала.

.user.ini: настройки каталога под CGI/FastCGI

На хостинге часто нельзя править общий php.ini, но разрешена конфигурация каталога приложения. .user.ini — механизм PHP только для CGI/FastCGI. Он не обрабатывается обычным CLI, встроенным php -S или PHP-модулем Apache.

PHP ищет пользовательские ini от каталога запрошенного PHP-файла к document root. Если файл находится вне корня документов, проверяется только его каталог. Допускаются режимы INI_USER и INI_PERDIR, а также соответствующий INI_ALL. Имя задаёт user_ini.filename; пустое имя отключает механизм.

Изменение не обязательно видно сразу
  1. Нужный CGI/FastCGI-процесс обслуживает файл приложения
  2. Читает разрешённые пользовательские ini для его каталога
  3. Использует кэш: user_ini.cache_ttl по умолчанию 300 секунд
  4. После применения проверяем текущее значение в этом HTTP-контексте
.user.ini для каталога приложения под CGI/FastCGIФрагмент или команда
upload_max_filesize = 8M
post_max_size = 10M
display_errors = Off

Предусловия: сайт действительно работает через CGI/FastCGI, механизм per-user ini включён, имя файла по настройке user_ini.filename — .user.ini, сервер допускает эти директивы. Не относится к CLI или встроенному php -S. Значения — учебный пример: 10M больше 8M, чтобы оставить место остальным полям и обрамлению POST; полный маршрут проверки загрузки разобран в главе uploads.

Не переименовывайте .htaccess в .user.ini: у них разные синтаксис и обработчик. После изменения учитывайте TTL кэша, а также ограничения администратора. Ожидание пяти минут — лишь стандартное значение, не обещание хостинга. Точный срок берут из действующей user_ini.cache_ttl.

Потребность «локально лимит менялся, на хостинге получаю 500» описана в обсуждении смены лимитов. Современное решение начинается с выяснения SAPI и разрешённого механизма, а не с подавления ini_set через @.

.htaccess, конфигурация Apache и настройки пула FPM

Файл .htaccess читает Apache при разрешённых переопределениях. Директивы php_value и php_flag доступны для PHP как модуля Apache. При Apache, передающем запросы FPM, наличие самого Apache недостаточно. Nginx вообще не читает .htaccess.

Сначала уточните SAPI и правила сервера. Иначе добавление php_value способно дать HTTP 500 до выполнения вашего скрипта; это не ошибка тела PHP-файла. Такой случай — вопрос о post_max_size и Internal Server Error.

Куда пишемКто понимает записьЧто нельзя переносить
php.ini / .user.iniПарсер настроек PHP в соответствующем режимеНе вставляем команды php_value с пробелами
.htaccess с mod_phpApache и PHP-модульНе считаем этот путь совместимым с FPM
Конфигурация пула FPMМенеджер FPMНе подменяем её файлом .user.ini
.htaccess только для PHP как модуля ApacheФрагмент или команда
php_flag display_errors Off
php_value upload_max_filesize 8M
php_value post_max_size 10M

Предусловия: Apache действительно загружает PHP модулем, эти директивы разрешены администратором для .htaccess через AllowOverride (Options или All), место файла соответствует нужному каталогу. Здесь нет знака =. Для логического значения применён php_flag, для размера — php_value. При Apache→FPM этот механизм PHP не становится доступным автоматически; чужой сервер может вернуть HTTP 500.

В серверной конфигурации Apache существуют php_admin_value и php_admin_flag: они не разрешены в .htaccess, и программа не отменяет их через ini_set. В php_value числовые PHP-константы из кода, например E_ALL, не вычисляются как в php.ini. Не переносите пример без проверки формата.

Фрагмент уже существующего пула FPM: запрет вывода ошибокФрагмент или команда
php_admin_flag[display_errors] = off
php_admin_flag[log_errors] = on

Это строки для конфигурации выбранного пула, а не .user.ini или обычного php.ini; полного пула здесь нет. Предусловия: администратор знает активный FPM, пул и способ безопасного применения его конфигурации. php_admin_flag закрепляет настройку так, что ini_set её не переопределяет. В этой работе FPM и его конфигурация не менялись.

Для FPM есть отдельные php_value/php_flag и php_admin_value/php_admin_flag в синтаксисе пула. Admin-вариант нельзя переопределить ini_set. Приведённый фрагмент объясняет границу полномочий; создание пула, адрес FastCGI, управление процессами и безопасный reload требуют отдельного полного урока.

Обычные секции ini и условные HOST/PATH

Заголовки [PHP], [Date] помогают человеку группировать строки основного ini; они не создают отдельную область видимости PHP-кода. Особый случай — [PATH=...] и [HOST=...]. Эти условные секции применяются только в CGI/FastCGI к подходящему пути или хосту.

Это также не то же самое, что секция [pool-name] в конфигурации FPM: похожие квадратные скобки не означают одинаковое назначение. В условных секциях нельзя загружать extension и zend_extension.

ЗаголовокОбласть смысла
[Date]Визуальная группа директив в основном ini
[PATH=/srv/lesson/public]Настройки подходящего пути в CGI/FastCGI
[HOST=lesson.example.test]Настройки указанного хоста в CGI/FastCGI
Условные секции основного ini для CGI/FastCGIФрагмент или команда
[PATH=/srv/lesson/public]
display_errors = Off

[HOST=lesson.example.test]
display_errors = Off

Фрагмент применим только к CGI/FastCGI. PATH выбирает область по пути, HOST — по имени хоста. Это два независимых условных блока, не последовательность запросов. Путь и имя учебные: перенесённый буквально фрагмент не настроит ваш сайт. extension и zend_extension в таких секциях загружать нельзя.

Официальное описание этих секций находится в List of php.ini sections. Проверка простым php -r или запуском CLI-файла не доказывает их действие для HTTP-запроса. Пограничные случаи совпадений и применение на реальном сервере остаются для серверного практикума.

Значение из окружения процесса

При нескольких учебных окружениях бывает удобно оставить одинаковый ini, а одно значение задать окружением запуска. Запись ${NAME} подставляет переменную окружения. С PHP 8.3 форма ${NAME:-fallback} задаёт запасной вариант для незаданной переменной. Наличие переменной с пустой строкой — другой случай: запасной вариант не применяется.

Что видит PHP в LESSON_MEMORYКакое значение получает memory_limit
Непустая строка, например 256M256M из окружения процесса
Переменная не заданаЗапасные 128M из ini
Переменная существует, но пустаПустое значение; для memory_limit это ошибка настройки, не выбор 128M
PHP 8.3+: значение из окружения с запасным вариантомФрагмент или команда
memory_limit = ${LESSON_MEMORY:-128M}

Предусловие: PHP 8.3+ и контролируемое окружение запуска. Если LESSON_MEMORY не задана, используется 128M. Пустая, но существующая переменная не включает запасной вариант: не задавайте лимит пустой строкой. Это синтаксис ini, не PHP-переменная со знаком $. Переменная должна существовать в окружении самого PHP-процесса; её наличие в вашем терминале не доказывает наличие у службы FPM. Здесь переменные компьютера не изменяются.

Строки таблицы — альтернативные исходы. Не путайте это с массивом $_ENV и переменной $name в PHP-коде. Службы могут получать другое окружение; FPM по умолчанию очищает его, кроме явно разрешённых значений. Не используйте такие подстановки для незаметной передачи секретов в публичные диагностические отчёты.

Внутри действия: восстановить настройку даже при раннем возврате

Когда настройка нужна только одному отчёту, важно не изменить поведение следующей операции. После базовых функций и управления выходом и finally рассмотрите полный небольшой пример. function reportTime объявляет действие без входных аргументов; : string означает строковый результат. return передаёт строку месту вызова.

try обозначает участок работы, finally — действие при выходе из него, включая return. date("H:i", 0) форматирует заданный момент как часы и минуты в текущем часовом поясе. Настройка меняется до вызова date, а затем восстанавливается.

Один отчёт не меняет следующий
  1. Перед вызовом UTC
  2. reportTime временно выбирает Asia/Tokyo
  3. date для момента 0 возвращает 09:00
  4. finally возвращает UTC, затем echo получает результат
Отчёт со своей временной настройкой и восстановлениемСамостоятельный пример
<?php
ini_set('date.timezone', 'UTC');

function reportTime(): string
{
    $before = ini_set('date.timezone', 'Asia/Tokyo');
    if ($before === false) {
        return 'Не удалось настроить часовой пояс';
    }
    try {
        return date('H:i', 0);
    } finally {
        ini_set('date.timezone', $before);
    }
}

echo "В отчёте: ", reportTime(), "\n";
echo "После отчёта: ", ini_get('date.timezone'), "\n";
Ожидаемый результат
В отчёте: 09:00
После отчёта: UTC

Самостоятельный учебный CLI-запуск без административных ограничений. Время 0 — начало Unix-отсчёта, поэтому результат определён, а не зависит от текущих часов. finally выполняется и при return, возвращая прежнюю настройку. Для реального приложения предпочтительнее явный DateTimeZone у операции: глобальная настройка может влиять на соседний код. Этот пример нужен для понимания области действия ini_set и восстановления.

Установка UTC в начале сделана для самостоятельного воспроизводимого опыта. В библиотеке не нужно навязывать её всему приложению. Ещё лучше передавать часовой пояс конкретному объекту даты, как показано в главе дат, тогда глобальная настройка вообще не меняется.

Практика: проверить причину, а затем выбрать место изменения

Задание 1. Вы исправили C:\Tools\PHP\php.ini, но сайт по-прежнему показывает прежний лимит. Предложенное решение: сначала прочитать SAPI, основной и дополнительные ini у сайта, затем действующее значение. Не считать CLI-доказательство доказательством HTTP.

Задание 2. ini_set вернул false для upload_max_filesize. Решение: найти режим INI_PERDIR и выбрать разрешённый startup/per-directory механизм. Оператор @ скрывает диагностику, но не выдаёт права на изменение.

Задание 3. После временной настройки внешний код должен получить своё прежнее значение. Решение: сохранить возврат ini_set, отличить false, восстановить прежнюю строку при выходе. ini_restore может вернуть другое — исходное — значение.

Задание 4. В .user.ini записали 8M и сразу не увидели эффекта. Решение: проверить CGI/FastCGI, имя user_ini.filename, расположение относительно исполняемого файла, TTL и admin-ограничения. Если это CLI, ожидание TTL не поможет.

Задание 5. display_errors=Off убрал сообщение из страницы. Что ещё проверить? Решение: правильный HTTP-ответ приложения и фактическую запись диагностики в доступный только обслуживающим людям журнал. Молчание страницы не означает исправление ошибки.

Рабочий порядок: зафиксировать исходный путь и значение → определить разрешённый уровень → изменить одну настройку в контролируемом окружении → применить её способом выбранного SAPI → проверить результат → сохранить путь возврата. В этой главе освоены основы; полные серверные, платформенные и расширенные варианты остаются самостоятельными разделами официального руководства.

Откуда взялось значение: основной ini, scan-файлы и выбранный SAPI

Вы изменили memory_limit, а программа продолжает видеть другое значение. Прежде чем повторно редактировать файлы, составьте цепочку загрузки. Есть выбор основного ini, дополнительные scan-файлы и последующие переопределения. Наличие php.ini в каталоге проекта не означает, что CLI его читает.

Первый этап: установленный SAPI может задать путь явно — -c у CLI/CGI, PHPIniDir у Apache. Далее участвуют PHPRC, Windows-registry при соответствующей платформе и пути поиска сборки. Точное правило нужно сверять с выбранным SAPI; полный наблюдаемый результат показывает --ini для CLI.

Кандидат основного ini по порядку PHP.netГраница
SAPI-specific путь: -c / PHPIniDirДолжен относиться к реально запущенному исполнителю
PHPRCОкружение именно процесса, а не соседнего терминала
Windows IniFilePath по версии x.y.z → x.y → x, затем общий ключ32/64-разрядное представление реестра зависит от PHP и ОС
Рабочий каталогCLI пропускает этот кандидат
Каталог веб-сервера для SAPI-module либо PHP на WindowsЗависит от интерфейса
Windows-каталог либо Unix compile-time config pathНе причина создавать глобальный ini без необходимости

Если найден php-SAPI.ini, он используется вместо общего php.ini: например, php-cli.ini для CLI. Не угадывайте имя другого SAPI по имени службы; смотрите его фактическое имя. На Unix изменение current directory сервером при старте также объясняет неожиданный путь.

Второй этап: после основного файла PHP читает *.ini из scan-каталогов. Внутри каждого каталога действует алфавитный порядок, а каталоги идут в заданном порядке. -c не отключает scan; -n отключает чтение ini. PHP_INI_SCAN_DIR меняет набор каталогов для процесса.

Вывести только наличие загруженных слоёв, без внутренних путейПример для указанного окружения
<?php
echo "main:", php_ini_loaded_file() === false ? 'none' : 'loaded', "\n";
echo "scan:", php_ini_scanned_files() === false ? 'none' : 'loaded', "\n";
Ожидаемый результат
main:none
scan:none

Показанный результат получается при запуске php -n: ini-файлы не читаются. При запуске с основным php.ini первая строка будет main:loaded; при наличии дополнительных файлов вторая будет scan:loaded. Функции возвращают путь/список либо false, а === false сравнивает именно отсутствие. Это диагностический пример с результатом, зависящим от окружения: общий прогон проверяет синтаксис, отдельная проверка запуска с -n подтвердила показанный вывод. Пример не раскрывает внутренние пути посетителю.

Запись двух scan-каталогов: разные разделителиФрагмент или команда
Unix:   /opt/lessons/conf.d:/opt/lessons/overrides
Windows: C:\PHP Lessons\conf.d;C:\PHP Lessons\overrides

Это карта значения PHP_INI_SCAN_DIR, не команды оболочки. На Unix разделитель :; на Windows ;. Пустой компонент списка включает compile-time scan-каталог на этом месте; он не означает «ничего не читать». Поэтому двоеточие в начале/конце может добавить неожиданную группу ini.

Внутри ini можно использовать ${NAME}, с PHP8.3 — ${NAME:-fallback}. В проверенном PHP8.5 fallback относится к отсутствующей переменной; существующая пустая строка не подменяется запасным значением. Не считайте эту запись универсальной проверкой корректности числа. Подробный минимальный разбор есть в базовой главе конфигурации.

Упражнение: главный ini содержит128M, scan-файл90-memory.ini содержит256M, а команда вызвана с -d memory_limit=192M. Какое значение ожидается в новом CLI?192M при отсутствии дальнейшего изменения в коде. Проверка такого приоритета важнее, чем поиск «единственно правильного» php.ini на всём диске.

Где разрешено менять настройку: серверный администратор и приложение

Разработчик хочет временно изменить отображение ошибки; администратор хочет удержать обязательную политику. INI-моды описывают, где параметр допускает изменение. Они не являются значением самого параметра и не заменяют проверку результата ini_set.

INI_USER разрешает уровень скрипта, INI_PERDIR — уровень каталога/конфигурации до выполнения, INI_SYSTEM — системную настройку запуска, INI_ALL объединяет возможности. Отдельные директивы имеют комбинированные маски и специальные ограничения. Считать любое число access равным ровно одной константе недостаточно.

Временно изменить разделитель вывода query и вернуть егоСамостоятельный пример
<?php
$before = ini_get('arg_separator.output');
$changed = ini_set('arg_separator.output', ';');
echo $changed === false ? "change:rejected\n" : "change:accepted\n";
echo "current:", ini_get('arg_separator.output'), "\n";
ini_set('arg_separator.output', $before);
echo ini_get('arg_separator.output') === $before ? "restored:yes\n" : "restored:no\n";
Ожидаемый результат
change:accepted
current:;
restored:yes

Самостоятельный безопасный CLI-опыт. $before сохраняет строку; ini_set возвращает прежнее значение или false. Сравнение === false не путает отказ с прежней пустой строкой. В конце возвращаем сохранённое значение. Это пример изменяемой INI_ALL-настройки; он не даёт право менять любую директиву.

При PHP как модуле Apache есть php_value для значений и php_flag для on/off. Они допускают INI_ALL/INI_PERDIR в применимом контексте. php_admin_value/php_admin_flag задаются в серверной конфигурации, не в .htaccess, и запрещают переопределение скриптом. Для FPM используются одноимённые записи с квадратными скобками в pool; эти два формата не надо смешивать.

Только mod_php: локальная политика виртуального хостаФрагмент или команда
php_flag display_errors Off
php_admin_flag log_errors On
php_admin_value memory_limit 128M

Apache-конфигурация с загруженным PHP-модулем. Для Apache+FPM эти директивы не являются способом изменить PHP: используйте pool/ini применимого SAPI. Даже изменяемую обычно memory_limit код не переопределит после административной установки. Пример не исполнялся.

PHP-константы вроде E_ALL разбираются в php.ini, но не обязаны существовать в конфигурации Apache или строках Windows-registry. Там числовая маска должна соответствовать целевой версии: не переносите число старого E_ALL без проверки. Для boolean в Apache используйте php_flag, а не php_value.

Windows PHP также имеет историческую per-directory настройку через HKLM\SOFTWARE\PHP\Per Directory Values и вложенные ключи пути. Значения строковые, работают для каталога и потомков, PHP-константы не вычисляются; здесь разрешены INI_USER, не INI_PERDIR. Это отдельный механизм от IniFilePath, который выбирает главный файл.

Для понимания существующей установки достаточно прочитать эти настройки с администратором и сопоставить с процессом. Учебный опыт не требует записи в HKLM. На64-битной Windows учитывайте представление реестра32-битного PHP; ключ, который видит одна программа, может отличаться от просматриваемого другой.

Упражнение: ini_set вернул false после php_admin_value, но та же директива обычно изменяема. Решение: найден дополнительный административный запрет; удаление проверки false лишь скроет проблему. Настройку меняет владелец серверной политики, если задача действительно этого требует.

.user.ini и условные секции: настройки до начала скрипта

Два сайта на одном исполнителе могут иметь разные ограничения. Для CGI/FastCGI PHP умеет искать .user.ini от каталога запрошенного PHP-файла вверх до document root. CLI и встроенный php -S этот механизм не применяют. Если файл вне document root, правила поиска отличаются: PHP рассматривает только его каталог.

В .user.ini доступны INI_USER/INI_PERDIR, имя файла выбирает user_ini.filename, пустое имя выключает механизм. user_ini.cache_ttl обычно300секунд: изменение не обязано появиться в следующем запросе. Настройки читаются до выполнения тела файла; их задача отличается от ini_set посередине программы.

.user.ini для учебного FastCGI-каталогаФрагмент или команда
upload_max_filesize = 2M
post_max_size = 3M

Файл в своём учебном каталоге под document root; SAPI должен быть CGI/FastCGI и разрешать механизм. Предел POST больше одиночного файла, потому что тело содержит дополнительные поля и multipart-разметку. Эти строки не включают обработку загрузки и не проверены через HTTP в этой партии.

Проверяйте ограничение настоящим запросом в отдельной среде после истечения TTL/обновления процессов. Один ini_get покажет настройку, но не докажет, что приложение корректно различает отказ сервера, пустой POST и ошибку конкретного файла. Код обработки загрузки относится к соответствующей веб-главе.

Другой механизм — секции [PATH=...] и [HOST=...] внутри главного ini. Они действуют для CGI/FastCGI, а не являются обычными декоративными [PHP]-заголовками. PATH выбирает путь, HOST — имя хоста; startup-директивы вроде extension и zend_extension такими секциями не управляются.

В главном ini: ограничить каталог учебного сайтаФрагмент или команда
[PATH=/srv/php-lessons/public]
memory_limit = 96M

[HOST=lessons.example.test]
display_errors = Off

Контекст CGI/FastCGI с указанным document root и отдельно настроенным учебным именем хоста. .test — демонстрационное имя; DNS/hosts не настраивались. Для реального опыта нужно проверить каждый путь/host через HTTP и границы соседнего сайта. Значения условных секций защищены от переопределения пользовательским ini/кодом в применимом контексте.

ЗадачаПодходящий механизмНеподходящая подстановка
Локальная CLI-проверка другого ini-c и при необходимости -n/-d.user.ini рядом с файлом
Разрешённая настройка FastCGI-каталога.user.ini с учётом TTLphp_value в .htaccess без mod_php
Административный предел FPM poolphp_admin_value[имя]Надежда, что приложение не вызовет ini_set
Изменить список загружаемых расширенийНастройки запуска соответствующего PHPextension в [PATH] или .user.ini

Упражнение: рядом с CLI-файлом лежит .user.ini, но лимит не изменился. Решение: это ожидаемо для CLI; используйте явные параметры запуска. Упражнение: после правки FastCGI .user.ini часть запросов ещё старая. Решение: исследовать cache TTL и живые процессы, а не добавлять ту же директиву во все найденные файлы.

Полная эксплуатационная проверка этих правил требует отдельной CGI/FastCGI-среды, нескольких каталогов и запросов с разными host. В этой Windows CLI-партии выполнены самостоятельные языковые опыты, а такие HTTP-сценарии явно остаются непроверенными.

Windows INI: поиск версии и разрядности без редактирования реестра

На машине несколько PHP, а найденный php.ini лежит не рядом с ожидаемым php.exe. Помимо явного -c/PHPRC, Windows PHP умеет искать IniFilePath в реестре. Сначала проверяют вывод php --ini полного пути исполнителя: это наблюдение безопаснее попытки сразу исправить глобальный registry. Реестр — системная база настроек; ошибочная запись влияет на другие процессы.

Для совпадающей разрядности PHP/ОС используется HKLM\SOFTWARE\PHP, для 32-bit PHP на 64-bit Windows — соответствующее 32-bit view (WOW6432Node). Внутри рассматриваются более точная версия x.y.z, затем x.y, затем x и общая настройка. Явный SAPI-specific путь и PHPRC участвуют раньше. В тексте PHP.net встречается опечатка WOW6421Node; вручную создавать ключ с таким именем не надо.

Путь действия: Windows INI: поиск версии и разрядности без редактирования реестра
  1. Полный путь php.exe и его разрядность
  2. Явный путь / PHPRC / соответствующий registry view
  3. Найденный основной ini
  4. --ini подтверждает результат поиска
PowerShell: прочитать существующие представления registryФрагмент или команда
reg.exe query HKLM\SOFTWARE\PHP /s /reg:64
reg.exe query HKLM\SOFTWARE\PHP /s /reg:32

Предусловие: 64-bit Windows, разрешено чтение HKLM. /reg выбирает view, /s показывает подветки. Если ключ отсутствует, reg сообщает об этом и возвращает ненулевой код; это нормальная причина не найти registry-конфигурацию, а не доказательство сломанного PHP. Команды ничего не записывают. Не публикуйте чужие локальные пути из отчёта без необходимости.

Per Directory Values — другой механизм: значения для c:\inetpub\wwwroot находятся под соответствующей иерархией c\inetpub\wwwroot и распространяются на подкаталоги. Это string values с именами директив, применимы лишь INI_USER-изменения; INI_PERDIR и PHP-константы так не задают. Наличие общей IniFilePath и per-directory значения имеет разный смысл. На управляемом IIS обычно понятнее явная конфигурация FastCGI/PHPRC и отдельный pool, чем скрытая новая registry-зависимость.

Практика: не меняя registry, составьте карту «полный php.exe → разрядность → main ini → scanned ini». Сравните с handler php-cgi.exe сайта. Работа CLI не подтверждает Per Directory Values/CGI-поведение: для этого нужен отдельный закрытый HTTP стенд.

Несколько INI: порядок чтения, текущие значения и условные секции

Настройка присутствует в двух файлах; нужно понять, какая применяется. В нормальном startup сначала читается основной ini, затем дополнительные .ini по порядку каталогов, внутри каталога — по алфавиту. PHP_INI_SCAN_DIR может перечислять несколько каталогов с PATH_SEPARATOR данной ОС; пустой элемент включает compiled-in scan directory. Это отличается от пустого списка дополнительных файлов и может неожиданно вернуть системные настройки.

INI умеет ссылаться на уже известное значение через ${имя}. Это не PHP-переменная с долларом и не shell-команда. Следующий пример читает только учебный текст; он не меняет ini работающего PHP. parse_ini_string возвращает массив прочитанных значений. INI_SCANNER_RAW сохраняет строки без вычисления специальных значений.

Путь действия: Несколько INI: порядок чтения, текущие значения и условные секции
  1. Startup: основной ini
  2. Каталоги scan в заданном порядке
  3. Допустимые локальные/административные значения
  4. ini_get наблюдает этот процесс
Проверить свойство учебного INI до использованияСамостоятельный пример
<?php
$text = "[report]\nname=stock\nlimit=20\n";
$settings = parse_ini_string($text, true, INI_SCANNER_RAW);
echo $settings['report']['name'], ': ', $settings['report']['limit'], "\n";
Ожидаемый результат
stock: 20

Строка [report] создаёт группу данных при втором аргументе true. ['report']['name'] читает значение внутри группы. Эта произвольная секция не является условной секцией php.ini и ничего не настраивает в runtime. Здесь учимся отличать текст INI от его применения системой.

Поздняя запись одного ключа в учебном INI-текстеСамостоятельный пример
<?php
$text = "limit=20\nlimit=30\n";
$settings = parse_ini_string($text);
echo $settings['limit'], "\n";
Ожидаемый результат
30

В учебном массиве остаётся последнее значение одинакового ключа. limit — произвольное имя данных, не директива PHP. Этот пример не моделирует режимы INI_SYSTEM/административный запрет или загрузку extension: у настоящих директив есть дополнительные правила.

Добавить каталог к текущему include_path на UnixФрагмент или команда
include_path = ${include_path} ":/srv/lesson/lib"

Фрагмент настоящего ini для собственного Unix PHP: ${include_path} ссылается на известное значение конфигурации, двоеточие разделяет пути. На Windows разделитель — точка с запятой. Не путайте это с произвольной переменной, объявленной предыдущей строкой в parse_ini_string: такой пользовательский ключ сам по себе не становится ini-переменной. Здесь изменение настройки не выполнялось.

МеханизмКогда/где действуетЧто не обещает
Основной php.ini и scanned .iniStartup конкретного PHP/SAPIСохранение файла не обновляет уже работающих workers
.user.iniCGI/FastCGI, разрешённые INI_USER/INI_PERDIR, cache TTLCLI/php -S не доказывают её действие
[HOST=имя] / [PATH=путь]Условные секции для CGI/FastCGIНельзя подключать extension/zend_extension в этих секциях
Apache php_admin_* / FPM php_admin_*Административно закреплённые значенияini_set не обходит запрет
ini_get / ini_get_allНаблюдение текущего процессаДругой SAPI может иметь иные значения/доступность

Для вложенной .user.ini PHP идёт от каталога запрошенного файла к document root; файл вне document root требует особого учёта пути поиска. user_ini.cache_ttl объясняет задержку, пустое user_ini.filename выключает поиск. HOST/PATH секции — специальная конфигурация PHP, обычные [mail] или [report] в php.ini не создают такие правила. Указание display_errors=On в dev HOST применимо только если реальный сервер передаёт ожидаемые данные хоста; не полагайтесь на непроверенный заголовок клиента как на контроль доступа.

Практика: в отдельном CGI/FastCGI стенде сравните root/a.php и root/nested/b.php с разрешённой директивой, дождитесь TTL либо перезапустите test pool, затем проверьте admin override. Здесь выполнены только два изолированных разбора INI-текста; реальное HTTP-наследование остаётся отдельно отмеченным испытанием.

configure: выбрать свойства ещё не собранного PHP

Нужен PHP с определённым SAPI или отладочная сборка для разбора сбоя расширения. Настройки php.ini не могут добавить код, которого нет в бинарном файле. configure работает раньше компиляции: проверяет систему и записывает правила для make. ini задаёт поведение уже собранного PHP. Эти этапы отличаются даже когда оба называют «конфигурацией».

Перед этим уроком пройдите исходную сборку с отдельным prefix. Команды ниже относятся к Unix/macOS shell внутри проверенного source tree выбранной версии PHP. ./ означает файл в текущей папке, --имя выбирает опцию, = связывает её со значением, кавычки сохраняют путь как один аргумент. Сборку и системную установку здесь не выполняли.

Что меняет каждый этап
  1. configure: есть ли библиотеки и какие возможности включить
  2. make: получить бинарные файлы
  3. make test: проверить код в этой сборке
  4. install: разместить выбранный prefix
  5. php.ini: настроить новый процесс
Минимальный отдельный CLI: конфигурация до сборкиФрагмент или команда
./configure --help
./configure --prefix="$HOME/php-lab85" --disable-all --enable-cli --disable-cgi --disable-phpdbg --without-pear

Предусловия: отдельное дерево исходников PHP 8.5, toolchain/зависимости из его README; если configure ещё нет, сначала buildconf с нужными генераторами. $HOME читается как существующая домашняя папка shell, не переназначается. --disable-all выключает по умолчанию включаемые расширения, но не удаляет обязательное ядро/JSON/OPcache 8.5. CLI явно оставлен; CGI/phpdbg/PEAR для этой задачи не нужны. Вторая команда создаёт файлы сборки в source tree, не устанавливает PHP.

Не вставляйте этот минимальный набор в существующую production-сборку: приложению могут быть нужны XML, mbstring, PDO и другие возможности. Отдельный prefix предотвращает прямую замену /usr/bin/php, но ещё не обеспечивает воспроизводимость. Сохраните tag/release, compiler, dependency versions, configure-команду, лог и результаты тестов. После сборки вызывайте полный путь нового php; PATH может по-прежнему выбирать старый.

Практика: укажите, какой из этапов исправляет каждую проблему: «не найден компилятор», «не собран mbstring», «memory_limit слишком мал», «терминал запускает старый PHP». Нельзя все четыре лечить изменением php.ini.

Пути, SAPI и библиотеки: осмысленно прочитать опции сборки

Установить две ветки PHP рядом полезно для проверки обновления. Для этого нужно развести бинарники, основной ini и каталог дополнительных ini. Параметры prefix/config-file-path/config-file-scan-dir решают разные части задачи: каталог установки не равен каталогу настроек. В готовом PHP смотрят php --ini и php-config, а не предполагают пути по имени архива.

Путь действия: Пути, SAPI и библиотеки: осмысленно прочитать опции сборки
  1. Отдельный prefix PHP
  2. Его bin и native-модули
  3. Его основной ini и conf.d
  4. Полный путь запуска выбирает этот комплект
Текущая опция / группаПрактический смыслЧто проверить
--prefix=…; --with-layout=PHP|GNUКорень и раскладка установленных файловГде получились bin, lib, man; не перезаписан системный PHP
--with-config-file-path=…Сборочный путь поиска основного iniphp --ini в новом процессе
--with-config-file-scan-dir=…Дополнительный каталог iniСписок parsed files и отсутствие модулей чужой ветки
--with-libdir=lib64; --disable-rpathКаталог библиотек / отказ от добавочных runtime search pathsЗависимости линковщика; lib64 не универсально для всех ОС
--enable-cli / --disable-cliНужен ли командный исполнительbin/php -v; отключение CLI ограничивает и инструменты на PHP
--enable-cgi / --disable-cgiCGI/FastCGI binary php-cgiНе путать с FPM; --disable-cgi не включает FastCGI
--enable-fpmОтдельный FPM SAPI для UnixPool/master конфигурация и listener после сборки
--with-apxs2=/путь/apxsApache 2 handler для выбранного ApacheВерсия Apache, MPM/TS и установка модуля
--enable-embed=shared|staticБиблиотека PHP для встраивания в программу на CHost-приложение и его linking; это не web server
--disable-phpdbg; --enable-phpdbg-debug; --enable-phpdbg-readlineСостав/отладочные возможности SAPI phpdbg в 8.5Нужна ли задача отладки; phpdbg не заменяет обычный CLI
--with-pear=… / --without-pearУстановка инфраструктуры PEARС PHP 7.4 она не устанавливается по умолчанию; Composer/PIE — отдельные инструменты
Развести конфигурацию собственной сборкиФрагмент или команда
./configure --prefix="$HOME/php-lab85" --with-config-file-path="$HOME/php-lab85/etc" --with-config-file-scan-dir="$HOME/php-lab85/etc/conf.d" --disable-all --enable-cli --disable-cgi --disable-phpdbg --without-pear

Предусловия как в предыдущем разделе. Это альтернативный configure для отдельной чистой сборочной папки. После успешных make/test/install создайте собственную конфигурацию в её etc, а не копируйте весь conf.d системного PHP. Один и тот же старый extension=… может указывать на несовместимый модуль.

Параметры конкретных расширений читают в их установочных разделах и ./configure --help этой версии. --enable-… обычно переключает возможность, --with-… может ещё задавать библиотеку/путь; это соглашение, а не универсальная гарантия. Современные расширения часто находят зависимости через pkg-config; старый --with-библиотека=/путь может больше не поддерживаться.

Практика: запланируйте два prefix без общего extension_dir и conf.d. Объясните, какие файлы приложения можно использовать повторно, а какие native-модули нужно пересобрать. Проектный lock не решает ABI-совместимость.

Debug, ZTS, таймеры и диагностика сборки

При падении собственного C-расширения нужен отладочный PHP. --enable-debug меняет сборку и её проверки; это не то же, что display_errors=On. Для обычной разработки PHP-файлов достаточно привычного исполнителя и настроек ошибок. ZTS добавляет поддержку потокобезопасного runtime для соответствующего embedding/SAPI; он не запускает ваш foreach параллельно.

Ниже — карта специального инструментария PHP 8.5.11. Не включайте все опции одновременно: sanitizer/coverage/debug сборки имеют особые требования и стоимость. Для исходной диагностики меняют один параметр, сохраняют отчёт и воспроизводящий тест.

Путь действия: Debug, ZTS, таймеры и диагностика сборки
  1. Минимальный воспроизводящий C-сбой
  2. Отдельный debug PHP
  3. Согласованно собранное расширение
  4. Тест и отчёт без секретов
Опция/семействоЗадача и граница
--enable-debug; --enable-debug-assertionsDebug build / дополнительные C assertions даже в release; отдельно от PHP assert()
--enable-ztsПотокобезопасная сборка; до PHP 8.0 на Unix использовалось имя --enable-maintainer-zts
--enable-zend-max-execution-timersPOSIX per-thread timers; PHP 8.1+, FreeBSD support 8.4+, default для ZTS с 8.3; нужны возможности ОС
--enable-sigchildСобственный обработчик SIGCHLD; может влиять на наблюдение дочерних процессов
--with-valgrind; --enable-dmallocИнтеграция диагностики памяти; нужны соответствующие инструменты/библиотеки
--enable-gcovПокрытие исходников C; не готовый отчёт покрытия пользовательского PHP
--enable-address-sanitizer; --enable-undefined-sanitizer; --enable-memory-sanitizerОтдельные compiler-инструменты для ошибок памяти/undefined behavior; memory sanitizer требует clang
--enable-werrorСделать предупреждения compiler ошибками; новая версия compiler может остановить старый код
--enable-dtraceСистемные tracing probes при поддержке toolchain/ОС
--enable-rtld-now; --enable-libgccРежим динамической загрузки / явная связь с libgcc; специальные linking задачи
--enable-system-glob; --disable-ipv6; --enable-fd-setsizeВыбор системной glob, сетевых возможностей и descriptor set; меняют свойства runtime
--enable-re2c-cgoto; --disable-fiber-asm; --disable-gcc-global-regs; --disable-zend-signalsНизкоуровневые варианты реализации/переносимости; решаются по целевой платформе и исходникам
--disable-short-tagsОтключить по умолчанию короткий <?; обычный <?php и <?= не исчезают
Отдельная debug-сборка для воспроизведения C-сбояФрагмент или команда
./configure --prefix="$HOME/php-debug85" --disable-all --enable-cli --disable-cgi --disable-phpdbg --without-pear --enable-debug

Предусловие: отдельное исходное дерево/сборочная папка с PHP 8.5 и compiler prerequisites. После make/test вызывают именно $HOME/php-debug85/bin/php. Release-модули не подставляют в debug runtime; требуемое расширение собирают согласованно. Здесь compiler не запускался.

Смысл max_execution_time зависит от платформы/сборки: обычный Unix ITIMER_PROF измеряет процессорное время, а POSIX per-thread timers считают прошедшее время, включая ожидание. По одной строке ini нельзя обещать одинаковое wall-clock завершение на всех PHP. Для внешнего процесса/HTTP отдельно задают соответствующий timeout; «30» не становится универсальным дедлайном всей системы.

Практика: подготовьте паспорт двух сборок — release и debug — и минимальный воспроизводящий PHP-файл. Отчёт об ошибке содержит версию, SAPI, compiler, расширения и фактический stderr, но не чужие секреты или полный дамп памяти с пользовательскими данными.

Исторические configure-флаги: сохранить смысл, проверить применимость

В официальном приложении configure.about перечислены и старые флаги, которых нет в проверенных core/SAPI исходниках PHP 8.5.11. Поэтому страница не является готовой командой для новой сборки. Ниже сохранены эти пункты дерева: читатель сможет распознать старый build script и выбрать современный путь. Сначала смотрят tag исходников и ./configure --help именно этой версии; warning unrecognized options нельзя принимать за успешное включение функции.

Путь действия: Исторические configure-флаги: сохранить смысл, проверить применимость
  1. Флаг из старого рецепта
  2. Задача, которую он решал
  3. Help конкретного PHP 8.5 source tree
  4. Поддерживаемый путь или явное отсутствие аналога
Пункт официального спискаКак читать при сопровождении
--enable-php-streamsИсторический экспериментальный переключатель; streams давно являются частью современного PHP, включать этим флагом файловые функции не нужно
--with-zlib-dirСтарый способ указать каталог; для актуального zlib смотрят установочную страницу расширения и pkg-config/--with-zlib текущего source tree
--with-tsrm-pthreadsИсторический выбор threading; для современного PHP нужен согласованный ZTS/toolchain маршрут
--with-apxs; --with-apache; --with-mod_charsetСтарые Apache 1.x/специальные варианты; современный Apache 2 handler использует --with-apxs2, а FPM вообще отдельный SAPI
--with-servletИсторическое Java/servlet-встраивание; не обещается в PHP 8.5
--enable-maintainer-mode; --enable-versioningПункты старого списка генерации/экспорта символов; не обнаружены в проверенных core/SAPI файлах 8.5.11, требуется проверка конкретного generated help
--enable-shared[=PKGS]; --enable-static[=PKGS]; --enable-fast-install[=PKGS]Опции libtool для библиотек/пакетов; не означают «встроить все расширения»
--with-gnu-ld; --disable-libtool-lock; --with-picВыбор linker/locking/PIC в поддерживающем их build system; не runtime-настройки php.ini
Сохранить справку своей версии перед переносом рецептаФрагмент или команда
./configure --help > configure-help.txt

Предусловие: configure уже подготовлен в отдельном source tree. > записывает stdout в файл текущей папки и перезаписывает существующий configure-help.txt, поэтому выберите новый файл при необходимости. Содержимое зависит от тега, платформы и добавленных расширений. Здесь генератор/сборка не исполнялись.

Если старый recipe использует отсутствующую опцию, выясните желаемый результат: например, передача PHP-запросов Apache сейчас решается FPM или актуальным handler, а не оживлением Apache 1.x. Отсутствующая возможность может требовать архитектурной замены; не заменяйте имя флага на похожее наугад. Архив старого PHP нужен для анализа совместимости, а не для публичного сервера без поддержки.

Практика: возьмите один старый флаг из таблицы, найдите его задачу и запишите современный эквивалент либо отсутствие прямого эквивалента. Не считайте тишину configure доказательством наличия функции: после сборки нужна проверка binary и полезного действия.

Проверить сборку и спланировать обновление без замены рабочего PHP

Команда make завершилась, но это только компиляция. Перед установкой нужны тесты и повторяемый артефакт. Release архив получают с официальной страницы выбранного выпуска, сверяют опубликованную подпись/контрольную сумму и сохраняют имя исходника. Git tag/commit фиксирует иной путь подготовки; README выбранного тега определяет compiler и генераторы.

После неуспешного configure найдите первую полезную причину в config.log: ошибка compiler, development headers, pkg-config или неподдерживаемая опция. После неуспешного make изучите первую ошибку compiler, а не только финальное Error 2. Не смешивайте частично собранные объекты разных архитектур/веток в одной папке.

Изменение версии — проверяемый переход
  1. Сохраняем рабочий prefix и его ini
  2. Собираем новый prefix отдельно
  3. Выполняем PHPT и тесты приложения
  4. Проверяем новый SAPI в тестовой среде
  5. Переключаем конкретный launcher/handler
  6. При отказе возвращаем прежний комплект
Запустить выбранную область тестов исходниковФрагмент или команда
make test TESTS=tests/basic

Предусловие: сборка PHP в этом source tree успешно завершена; tests/basic — существующий каталог PHPT этого дерева. PHPT описывает вход и ожидаемый результат теста. Другие наборы могут требовать расширения/сервисы/переменные среды. Не отправляйте отчёт наружу автоматически: сначала исключите секреты и разберите FAIL/SKIP. Здесь make test не выполнялся.

SKIP означает непройденный сценарий из-за его условий, а не подтверждённую исправность. FAIL сравнивают с .out/.exp/.diff и воспроизводят минимально; flaky timing или locale проверяют отдельно, не удаляют тест ради зелёной строки. Сборка с критическим необъяснённым FAIL не становится рабочей только после make install.

На macOS сверяйте uname -m, выбранный SDK/compiler и архитектуру библиотек; смешение arm64/x86_64 часто проявляется при linking. На Solaris изучают требования конкретной ОС/compiler и поддерживаемые библиотеки: наличие старого Solaris пункта в PHP.net не доказывает наличие современного готового пакета. На Windows MSVC/SDK/build dependencies должны соответствовать целевому PHP. Этот урок даёт процедуру проверки; реальная сборка на этих ОС остаётся отдельным испытанием.

Практика: составьте migration record с предыдущим и новым prefix, конфигурацией, модульным составом, тестами и точкой возврата. Откат кода не откатывает изменённую схему базы автоматически: миграции данных согласуют отдельно.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.