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

Дерево руководства
Глава 90 · От основ к практике
Запуск программ: полный справочник, вывод и управление процессом
Как PHP вызывает Python/Node/CLI, принимает данные и ошибки, ждёт завершения и избегает путаницы shell, argv и pipe.
Есть готовый обработчик на Python: как передать ему работу из PHP
От PHP-задания до проверенного результата
Worker считает отчёт по заказам. Одного непустого текста недостаточно: родитель проверяет завершение и формат ответа.
- 1PHP → worker↓
Известная программа получает отдельные аргументы и данные stdin. Переменные PHP не становятся общими переменными другого языка.
- 2stdout: total=9000↓
Канал полезного результата. Может содержать только часть ответа при отказе.
- 3stderr и exit↓
Диагностика идёт отдельно; код завершения описывает результат по договору worker.
- 4Проверка PHP
Принять корректный полный отчёт либо отклонить задание, сохранив понятную причину.
proc_open создаёт процесс, proc_close ждёт завершения. Большие двусторонние pipe требуют отдельной схемы обмена, чтобы участники не ждали друг друга.
У магазина уже есть отчётный обработчик на другом языке или установленная программа, умеющая преобразовывать документы. Переписывать её ради PHP-сайта не обязательно: PHP проверяет задание, запускает известную программу, передаёт данные и принимает результат. Это оправдано, когда отдельная программа даёт нужную возможность. Для сложения двух цен отдельный процесс добавил бы только запуск, обмен и новые причины отказа.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
- Родитель PHP хранит переменные задания
- ОС создаёт отдельный процесс worker
- worker получает аргументы/входной поток, а не переменные PHP напрямую
- Родитель получает вывод и статус, проверяет их и продолжает
Чтобы увидеть механизм без установки Python, первый worker тоже написан на PHP, но запускается отдельным процессом. Затем практическая глава показывает равнозначные Python/Node.js workers. Все учебные запуски здесь используют собственные маленькие файлы и не обращаются к чужим сервисам.
Файл worker.php
<?php echo "ready\n";<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
$lines = [];
$last = exec($command, $lines, $exitCode);
if ($last === false || $exitCode !== 0) { throw new RuntimeException('Report failed'); }
echo 'Worker answered: ', $last, "\n";
Ожидаемый результат
Worker answered: ready
Сначала прочитайте worker.php: он выводит ready и заканчивается. Переменная last принадлежит родителю; слово ready пришло через вывод ребёнка, а не через общий участок памяти.
Выбрать функцию по нужному результату
Одна команда может дать три независимых результата: данные, диагностический текст и код завершения. Выбирайте API исходя из того, какие из них нужны вашему приложению.
- stdout: total=9000 — данные
- stderr: processed=2 — техническая запись
- exit: 0 — договор об успехе
- PHP проверяет договор и только затем публикует результат
| Инструмент | Куда попадает stdout | Как узнать завершение |
|---|---|---|
| exec | Массив строк и последняя строка в return | Выходной result_code; ждёт завершения |
| shell_exec | Одна полная строка | Нет отдельного кода; null неоднозначен |
| system | В вывод PHP; return — последняя строка | Выходной result_code |
| passthru | Сырые байты в вывод PHP; return не содержит байты | Выходной result_code |
| proc_open | Настраиваемые pipe/файлы/дескрипторы, stderr отдельно | Ресурс → status/close; запуск и ожидание разделены |
| popen / pclose | Один однонаправленный pipe | Проверить pclose; для двустороннего протокола proc_open |
stdout не обязан быть текстом, а stderr не обязан означать аварийную ошибку: многие программы пишут туда прогресс. Смысл exit!=0 тоже задаёт программа; у некоторых утилит разные ненулевые коды обозначают разные штатные результаты. Описание внешнего инструмента — часть контракта интеграции.
Среда запуска, ресурсы и доступность
Ветка Program execution входит в стандартную функциональность PHP, но разрешение запуска определяется сборкой, конфигурацией и правами процесса. Проверяйте именно CLI/FPM/Apache, где будет работать задача. Разные SAPI могут иметь разные php.ini, пользователя, PATH, рабочий каталог и доступ к файлам.
- PHP-процесс имеет конкретного системного пользователя
- Конфигурация могла отключить функцию
- ОС проверяет путь и права на программу/файлы
- Дочерняя программа работает с этими ограничениями
<?php
declare(strict_types=1);
foreach (['exec', 'proc_open', 'proc_close'] as $name) {
echo $name, ': ', function_exists($name) ? 'available' : 'unavailable', "\n";
}
Ожидаемый результат
exec: available
proc_open: available
proc_close: available
Это фактическая доступность тестового CLI. Она не обещает разрешения веб-хостинга. В PHP 8 disable_functions удаляет определение внутренней функции; проверка должна относиться к нужному окружению.
| Что вы держите | Как с ним работать |
|---|---|
| process resource от proc_open | Управление через proc_get_status/proc_terminate, освобождение и ожидание proc_close. Это не объект с методами и не просто число PID. |
| pipe stream в $pipes | Обычные функции потоков читают/пишут данные. Закрытие отдельного pipe не равно получению exit code. |
| файлы результата | Ограниченный закрытый каталог задания; хранение, права, квоты и очистка принадлежат приложению. |
У этой официальной ветки нет собственных INI-параметров или констант. Общие disable_functions, лимиты, ОС и политика сервиса всё равно важны. Для запрещённого запуска выбирайте поддерживаемую очередь/службу/авторизованный сервис. Не заменяйте одну запрещённую функцию другой ради обхода ограничений.
Shell-строка, argv и данные — три разных уровня
Shell — программа, которая разбирает командную строку: кавычки, перенаправления, конвейеры и подстановки. Она добавляет ещё один язык поверх PHP. В argv-массиве proc_open каждый элемент уже является отдельным аргументом; shell там не разбирает амперсанд как командный оператор.
- Доверенный абсолютный путь: какой исполняемый файл
- Фиксированная операция и проверенные отдельные аргументы
- Большие/сложные данные: stdin, например JSON
- Программа сама проверяет схему, диапазоны и допустимые опции
Не смешивайте HTML-экранирование и shell-экранирование. htmlspecialchars нужен перед выводом в HTML, escapeshellarg — только при формировании отдельного аргумента shell. Оба не нужны для элемента argv-массива. Программная опция --delete не становится допустимой лишь оттого, что передана одним аргументом.
Файл input.txt
Файл worker.php
<?php echo $argv[1];<?php
declare(strict_types=1);
$value = 'sale%!" & report';
$process = proc_open(
[PHP_BINARY, '-n', __DIR__ . '/worker.php', $value],
[0 => ['file', __DIR__ . '/input.txt', 'r'],
1 => ['pipe', 'w'], 2 => ['file', __DIR__ . '/error.txt', 'w']],
$pipes, __DIR__
);
if ($process === false) { throw new RuntimeException('Cannot start worker'); }
$received = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$exitCode = proc_close($process);
var_dump($received === $value, $exitCode);
Ожидаемый результат
bool(true)
int(0)
Никакой текст не интерпретируется как дополнительная команда. На Windows этот опыт проверен с PHP CLI, который использует совместимый разбор argv. Для другого бинарника отдельно проверяйте его правила.
Для JSON/произвольных байтов удобен stdin: он не зависит от предела длины командной строки, shell quoting и случайного раскрытия аргументов в списке процессов. При этом длину входа и вывода всё равно ограничивают. Секреты не включают в команды, журналируемые целиком.
Почему два работающих процесса могут навсегда ждать друг друга
Pipe имеет ограниченный системный буфер. Если родитель пишет большой ввод, не читая вывод, а ребёнок одновременно пишет большой вывод, не читая оставшийся ввод, оба могут заблокироваться. Такая ошибка не устраняется перестановкой двух строк stream_get_contents для всех случаев.
- PHP заполняет stdin и ждёт, когда ребёнок прочитает
- worker заполняет stdout и ждёт, когда PHP прочитает
- PHP ещё занят записью stdin
- worker ещё занят записью stdout → оба ждут
| Ситуация | Рабочая стратегия |
|---|---|
| Короткий известный запрос и короткий ответ | Простейший последовательный обмен допустим при строгой границе объёма и поведении worker. Закройте stdin после записи. |
| Большие двусторонние потоки POSIX | Неблокирующий цикл с одновременным обслуживанием stdin/stdout/stderr, учётом частичных записей, deadline и ограничений объёма. |
| Windows proc_open pipes | Нельзя механически перенести POSIX stream_select: он не поддерживает эти дескрипторы так же. Используйте проверенный process runner/платформенный supervisor или файловый протокол. |
| Разовый отчёт через файлы | Собственный каталог задания отделяет вход и оба выхода; нужны квоты, срок жизни, проверка ошибок диска и атомарная публикация. |
Маленькие примеры показывают конкретный вызов, а файловый runner с JSON связывает его с отчётом. Файлы устраняют именно взаимное заполнение pipe, но не дают бесплатный timeout и не ограничивают диск. Нужны также обработка исчезнувшей программы и проверка формата результата.
Код завершения, отмена, приоритет и стоимость
- Создать ID и известный вход
- Запустить и наблюдать до deadline
- При отказе/отмене остановить, затем подтвердить завершение
- Принять проверенный результат либо сохранить понятную причину отказа
Нельзя обещать, что proc_terminate остановит всё дерево процессов: shell/worker могут породить потомков. Для сервиса с несколькими пользователями задачу выносят в очередь и процесс под управлением supervisor, а HTTP возвращает ID и статус. Повторный запуск должен учитывать идемпотентность и уже созданные файлы.
Запуск отдельного процесса добавляет создание процесса, загрузку программы, передачу данных и переключение контекста. Для маленькой операции это может быть дороже самой работы. Не называйте exec быстрее system без измерения одинаковой задачи. Приоритет влияет на планирование при конкуренции, а не уменьшает число вычислений.
| proc_nice: Windows 8.5.11 | Класс текущего процесса |
|---|---|
| -10 и меньше | High |
| -9…-5 | Above normal |
| -4…4 | Normal |
| 5…9 | Below normal |
| 10 и больше | Idle |
Диапазон 5…9 проверен по win32/nice.c PHP 8.5.11: краткая таблица PHP.net с условием >5 пропускает границу 5. На Unix значение — прибавка nice, а не выбор этих классов. Повышенный приоритет без необходимости может ухудшить работу других задач. Учебные примеры изменяют только собственный отдельный CLI-процесс.
Задание: импортёр вернул текст, но запретил импорт
Worker проверяет товары, печатает checked=2 и выходит с кодом 4. Нужно получить обе вещи и вывести Import rejected, не выполняя никаких изменений в магазине. До просмотра решения решите, какую функцию выбрать и почему shell_exec здесь недостаточно.
- Есть непустой stdout checked=2
- Есть exit code 4
- Оба результата принадлежат одному запуску
- Ненулевой статус по договору отменяет импорт
Файл worker.php
<?php echo "checked=2\n"; exit(4);<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
$lines = [];
$last = exec($command, $lines, $exitCode);
if ($last === false || $exitCode !== 0) {
echo "Import rejected\n";
} else {
echo "Import allowed\n";
}
echo implode(' | ', $lines), "\n";
Ожидаемый результат
Import rejected
checked=2
Для следующего шага добавьте JSON-схему результата: даже exit=0 не делает произвольную строку корректными данными заказа. Готовые варианты плохого JSON и неверной схемы.
Полный указатель функций этой категории
Все одиннадцать функций официальной ветки собраны здесь. Карточки exec/proc_open сохраняют прежние адреса в практической главе; туда добавлен полный контракт, а ранние примеры сохранены.
| Функция | Что решить |
|---|---|
| escapeshellarg | Сформировать один аргумент shell-команды, сохранив пробелы внутри него. |
| escapeshellcmd | Экранировать метасимволы целой shell-строки, понимая, что границы аргументов при этом не защищены. |
| exec | Получить текстовый отчёт внешней программы и отдельно проверить её код завершения. |
| passthru | Передать сырые байты stdout в вывод PHP, например результат доверенного конвертера. |
| proc_close | Дождаться окончания своего процесса и освободить его ресурс, получив код завершения. |
| proc_get_status | Узнать, работает ли ваш дочерний процесс, и сохранить сведения о его завершении. |
| proc_nice | Изменить приоритет текущего PHP-процесса, например отдельного фонового worker. |
| proc_open | Настроить вход, выход и окружение отдельной программы; получить дескриптор для управления её жизнью. |
| proc_terminate | Попросить завершиться именно тому процессу, которым владеет ваш запуск. |
| shell_exec | Получить stdout целиком одной строкой, когда отдельный код завершения не требуется. |
| system | Показать текст, который печатает дочерняя программа, непосредственно в выводе PHP. |
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
systemПоказать текст, который печатает дочерняя программа, непосредственно в выводе PHP.
PHP 8.2+; изменения отмечены в тексте · standard
system(string $command, int &$result_code = null): string|falseПоказать текст, который печатает дочерняя программа, непосредственно в выводе PHP.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| command | Полная командная строка для shell, включая доверенный исполняемый файл и отдельно сформированные аргументы. Не команда из формы посетителя. Windows использует cmd.exe; для argv без shell нужен proc_open с массивом. |
| result_code | Выходной параметр с кодом завершения. Наличие вывода не заменяет его проверку. |
| Возврат и вывод | Все строки идут в вывод PHP, но возвращается только последняя строка без завершающих пробельных символов; false при отказе запуска. |
| Буферы | При работе серверным модулем PHP пытается сбрасывать серверный буфер после каждой строки. PHP, веб-сервер, прокси и браузер всё равно могут буферизовать; это не гарантия моментального появления строки у посетителя. |
| Ошибки | Общий механизм exec: предупреждение при невозможности запуска, ValueError для пустой/NUL строки в современном PHP. |
- worker пишет две строки
- system отправляет обе в вывод PHP
- last сохраняет только total=9000
- Дополнительный echo last повторил бы последнюю строку
Файл worker.php
<?php
echo "rows=2\n";
echo "total=9000\n";
<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
$last = system($command, $exitCode);
echo 'saved=', $last, '; exit=', $exitCode, "\n";
Ожидаемый результат
rows=2
total=9000
saved=total=9000; exit=0
system уже печатает строки. Возвращаемое значение — короткое напоминание о последней, а не полный отчёт.
Файл worker.php
<?php echo "<b>report</b>
";<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
ob_start();
try { $last = system($command, $exitCode); }
finally { $text = ob_get_clean(); }
if ($exitCode !== 0 || $last === false) { throw new RuntimeException('Report failed'); }
echo htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
Ожидаемый результат
<b>report</b>
ob_start включает буфер PHP: текст ещё не отправлен пользователю. После проверки он экранируется для HTML. Для получения строки удобнее exec/proc_open; этот опыт показывает разницу вывода и возврата, а не универсальный способ стриминга.
<?php
declare(strict_types=1);
foreach (['', "bad\0command"] as $command) {
try { system($command); }
catch (ValueError $error) { echo "Invalid command\n"; }
}
Ожидаемый результат
Invalid command
Invalid command
Это проверка входной строки, а не запуск неизвестной программы. Нулевой байт нельзя молча удалить, изменив смысл исходных данных. PHP 8+ сообщает ValueError.
passthruПередать сырые байты stdout в вывод PHP, например результат доверенного конвертера.
PHP 8.2+; изменения отмечены в тексте · standard
passthru(string $command, int &$result_code = null): ?falseПередать сырые байты stdout в вывод PHP, например результат доверенного конвертера.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| command | Полная командная строка для shell, включая доверенный исполняемый файл и отдельно сформированные аргументы. Не команда из формы посетителя. Windows использует cmd.exe; для argv без shell нужен proc_open с массивом. |
| result_code | Код завершения программы, записываемый в переменную. Проверять отдельно от возврата passthru. |
| Возврат | null при выполнении; false при невозможности запуска. Сами байты функция выводит, а не возвращает строкой. |
| Ошибки | E_WARNING при невозможности запуска. Пустая команда или NUL — ValueError с PHP 8.0. |
| HTTP | Content-Type и остальные заголовки задают до тела ответа. Уже переданные повреждённые/частичные данные нельзя отозвать после неуспеха конвертера. Если нужен атомарный ответ, сначала получите и проверьте результат. |
- worker пишет байты A, NUL, B
- passthru передаёт их в буфер PHP
- hex показывает 410042 без потери NUL
- Возврат null, код завершения проверяется отдельно
Файл worker.php
<?php fwrite(STDOUT, "A\0B");<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
ob_start();
try { $result = passthru($command, $exitCode); }
finally { $bytes = ob_get_clean(); }
echo bin2hex($bytes), "\n";
var_dump($result, $exitCode);
Ожидаемый результат
410042
NULL
int(0)
NUL внутри данных не равен NUL в командной строке. Буфер здесь маленький; для большого документа хранение в памяти требует отдельного решения.
Файл worker.php
<?php echo "PARTIAL"; exit(7);<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
ob_start();
try { $result = passthru($command, $exitCode); }
finally { $bytes = ob_get_clean(); }
if ($result === false || $exitCode !== 0) {
echo "Document rejected\n";
} else { echo $bytes; }
Ожидаемый результат
Document rejected
Worker успел выдать начало документа и завершился с кодом 7. Буфер не был опубликован. Прямой passthru без буфера уже отправил бы PARTIAL посетителю.
<?php
declare(strict_types=1);
foreach (['', "bad\0command"] as $command) {
try { passthru($command); }
catch (ValueError $error) { echo "Invalid command\n"; }
}
Ожидаемый результат
Invalid command
Invalid command
Это проверка входной строки, а не запуск неизвестной программы. Нулевой байт нельзя молча удалить, изменив смысл исходных данных. PHP 8+ сообщает ValueError.
shell_execПолучить stdout целиком одной строкой, когда отдельный код завершения не требуется.
PHP 8.2+; изменения отмечены в тексте · standard
shell_exec(string $command): string|false|nullПолучить stdout целиком одной строкой, когда отдельный код завершения не требуется.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| command | Полная командная строка для shell, включая доверенный исполняемый файл и отдельно сформированные аргументы. Не команда из формы посетителя. Windows использует cmd.exe; для argv без shell нужен proc_open с массивом. |
| Возврат | Весь stdout как строка; false при невозможности открыть pipe; null при отсутствии вывода или некоторых ошибках. Эти исходы не позволяют надёжно определить успешность программы. |
| Ошибки | E_WARNING при невозможности открыть pipe. Пустая/NUL командная строка отвергается ValueError в современном PHP. |
| Windows | Внутренний pipe открывается в текстовом режиме. Нельзя обещать сохранение произвольных бинарных данных; используйте явно бинарный поток или proc_open. |
| Синтаксис | Оператор обратных кавычек имеет то же назначение, но устарел с PHP 8.5. Здесь используется явная функция. |
- worker печатает две строки
- shell ждёт завершения
- shell_exec возвращает одну строку с переводами строк
- Кода завершения в возвращаемом значении нет
Файл worker.php
<?php
echo "rows=2\n";
echo "total=9000\n";
<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
$text = shell_exec($command);
if (!is_string($text)) { throw new RuntimeException('No report text'); }
echo str_replace("\n", '|', $text), "\n";
Ожидаемый результат
rows=2|total=9000|
В отличие от exec, переводы строк входят в результат. Проверка is_string подтверждает наличие текста, но не успешность вычисления.
Файл worker.php
<?php exit(4);<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
var_dump(shell_exec($command));
Ожидаемый результат
NULL
Worker завершился с ошибкой 4 без вывода. Worker с exit(0) без вывода тоже дал бы null. Для импортов и обновления файлов выбирают функцию с явным exit code.
Файл worker.php
<?php echo "partial"; exit(4);<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
var_dump(shell_exec($command));
Ожидаемый результат
string(7) "partial"
Вывод partial сохранился, хотя программа завершилась с кодом 4. Нельзя строить ветку успеха только на непустом тексте.
<?php
declare(strict_types=1);
foreach (['', "bad\0command"] as $command) {
try { shell_exec($command); }
catch (ValueError $error) { echo "Invalid command\n"; }
}
Ожидаемый результат
Invalid command
Invalid command
Это проверка входной строки, а не запуск неизвестной программы. Нулевой байт нельзя молча удалить, изменив смысл исходных данных. PHP 8+ сообщает ValueError.
escapeshellargСформировать один аргумент shell-команды, сохранив пробелы внутри него.
PHP 8.2+; изменения отмечены в тексте · standard
escapeshellarg(string $arg): stringСформировать один аргумент shell-команды, сохранив пробелы внутри него.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| arg | Одна строка-аргумент: например имя файла. Это не вся командная строка, не HTML и не массив argv. |
| POSIX | Окружает аргумент одинарными кавычками и обрабатывает внутренние одинарные кавычки. |
| Windows | Окружает двойными кавычками; %, ! и двойную кавычку заменяет пробелом. Обрабатывает обратные слеши по правилам платформы. Не обещает точную передачу любых данных. |
| LC_CTYPE | Обработка многобайтовых символов зависит от текущей locale; нераспознанные символы могут быть отброшены. Проверяйте реальные байты для нужной системы. |
| Возврат / отказ | Возвращает строку для shell. Нулевой байт отвергается ValueError; лимиты длины задаются реализацией/ОС. Это не способ обхода запрета запуска и не проверка допустимых опций программы. |
- Текст monthly report
- escapeshellarg добавляет системные кавычки
- shell передаёт worker один элемент argv
- worker получает monthly report целиком
Файл worker.php
<?php echo $argc - 1, "\n", $argv[1], "\n";<?php
declare(strict_types=1);
$command = escapeshellarg(PHP_BINARY) . ' -n ' . escapeshellarg(__DIR__ . '/worker.php');
$command .= ' ' . escapeshellarg('monthly report');
$lines = [];
exec($command, $lines, $exitCode);
echo implode("\n", $lines), "\n";
echo $exitCode, "\n";
Ожидаемый результат
1
monthly report
0
argc-1 — число аргументов после имени скрипта. Оно равно одному, хотя внутри названия есть пробел. Символы кавычек не нужны самим данным.
<?php
declare(strict_types=1);
$argument = 'sale%!"';
$quoted = escapeshellarg($argument);
echo PHP_OS_FAMILY === 'Windows'
? (str_contains($quoted, '%') || str_contains($quoted, '!') ? "Unexpected\n" : "Windows replaces data\n")
: "POSIX quoting keeps data\n";
try { escapeshellarg("a\0b"); }
catch (ValueError $error) { echo "NUL rejected\n"; }
Ожидаемый результат
Windows replaces data
NUL rejected
Проверенный результат относится к Windows. На POSIX первая строка будет POSIX quoting keeps data. Для передачи JSON, подписей и паролей не допускают такого изменения байтов: используйте stdin или argv без shell.
Экранирование не запрещает значение --output=...: внешняя программа может воспринять его как опцию. Ограничивайте допустимые аргументы; разделитель -- помогает только если конкретная программа его поддерживает. Не оборачивайте готовый результат escapeshellarg ещё одними кавычками и не прогоняйте всю собранную команду повторно через escapeshellcmd. Для proc_open с argv-массивом оба экранирования лишние.
Следующий шаг: escapeshellcmd; exec; proc_open.
escapeshellcmdЭкранировать метасимволы целой shell-строки, понимая, что границы аргументов при этом не защищены.
PHP 8.2+; изменения отмечены в тексте · standard
escapeshellcmd(string $command): stringЭкранировать метасимволы целой shell-строки, понимая, что границы аргументов при этом не защищены.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| command | Вся командная строка. Пробелы продолжают разделять аргументы; функция не выбирает разрешённую программу. |
| POSIX | Специальные символы получают обратный слеш; парные кавычки учитываются особо. Строка не превращается в один аргумент. |
| Windows | Для специальных символов, включая % и !, используется ^. Пробелы не защищаются, поэтому путь с Program Files всё ещё требует корректного построения команды. |
| LC_CTYPE | Нераспознанные многобайтовые символы могут отбрасываться: это зависит от locale. |
| Возврат / отказ | Возвращает обработанную строку. Нулевой байт вызывает ValueError. Не решает argument injection: нежелательные опции могут остаться отдельными аргументами. |
- Вход содержит monthly report
- escapeshellcmd оставляет пробел разделителем
- При подстановке получатся два слова
- escapeshellarg либо argv-массив сохраняет один элемент
<?php
declare(strict_types=1);
$text = escapeshellcmd('report & status');
echo str_contains($text, 'report ') ? "Spaces remain\n" : "Unexpected\n";
echo PHP_OS_FAMILY === 'Windows' ? (str_contains($text, '^&') ? "Caret escaping\n" : "Unexpected\n") : "POSIX escaping\n";
Ожидаемый результат
Spaces remain
Caret escaping
Никакая программа здесь не запускается. На POSIX второй результат отличается: POSIX escaping. Windows-строку нельзя использовать как готовое POSIX-экранирование для SSH-команды.
<?php
declare(strict_types=1);
$text = escapeshellcmd('report --mode=debug');
var_dump(str_contains($text, '--mode=debug'));
try { escapeshellcmd("report\0data"); }
catch (ValueError $error) { echo "NUL rejected\n"; }
Ожидаемый результат
bool(true)
NUL rejected
Имя report здесь учебный текст, он не исполняется. Функция не знает, какие режимы разрешены в вашем приложении. Не передавайте ей всю строку посетителя с расчётом получить безопасный запуск.
| Метасимволы POSIX | Особое правило |
|---|---|
| & # ; обратная кавычка | * ? ~ < > ^ ( ) [ ] { } $ обратный слеш, LF и байт FF | Экранируются обратным слешем. Для одинарной/двойной кавычки учитывается парность. |
| Windows: те же символы, а также % и ! | Используется ^; командная оболочка и разбор аргументов программы — разные уровни. |
| Пробел и --option | Не исчезают: остаётся возможность другого набора аргументов. |
Исторический сценарий — уже сформированная доверенная команда с намеренным набором отдельных аргументов. Для новой интеграции выбирайте фиксированный исполняемый файл и массив аргументов proc_open. Если shell действительно нужен, проверяйте структуру команды и каждый аргумент отдельно; универсальный sanitize_command не заменяет этот договор.
Следующий шаг: escapeshellarg; proc_open; exec.
proc_closeДождаться окончания своего процесса и освободить его ресурс, получив код завершения.
PHP 8.2+; изменения отмечены в тексте · standard
proc_close(resource $process): intДождаться окончания своего процесса и освободить его ресурс, получив код завершения.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| process | Живой дескриптор, полученный proc_open. Это не произвольный PID и не поток из popen. |
| Возврат | Код завершения; при внутренней ошибке -1. При сборке --enable-sigchild значение не определено. |
| Ожидание | Функция может блокироваться до завершения. Она закрывает связанные открытые pipe; нужный вывод следует прочитать до закрытия, а stdin — закрыть, когда ввод закончен. |
| PHP 8.3 | После proc_get_status сохраняется правильный exit code. До 8.3 последующий proc_close мог вернуть -1; учитывать старые рекомендации нужно по версии. |
| Повторный вызов | После закрытия resource недействителен. Повторное использование вызывает TypeError в современном PHP. |
- proc_open создал ресурс
- worker записал ready и завершился с 4
- proc_close дождался и вернул 4
- Ресурс закрыт; результат задания отклоняется
Файл worker.php
<?php echo "ready"; exit(4);Файл input.txt
<?php
declare(strict_types=1);
$process = proc_open(
[PHP_BINARY, '-n', __DIR__ . '/worker.php'],
[0 => ['file', __DIR__ . '/input.txt', 'r'],
1 => ['file', __DIR__ . '/output.txt', 'w'],
2 => ['file', __DIR__ . '/error.txt', 'w']],
$pipes,
__DIR__
);
if ($process === false) { throw new RuntimeException('Cannot start worker'); }
$exitCode = proc_close($process);
echo $exitCode, "\n";
echo file_get_contents(__DIR__ . '/output.txt'), "\n";
Ожидаемый результат
4
ready
Ненулевой код пришёл от нашего worker, а не от PHP-исключения. Ресурс освобождён независимо от успешности бизнес-действия.
Файл worker.php
<?php echo "ready"; exit(4);Файл input.txt
<?php
declare(strict_types=1);
$process = proc_open(
[PHP_BINARY, '-n', __DIR__ . '/worker.php'],
[0 => ['file', __DIR__ . '/input.txt', 'r'],
1 => ['file', __DIR__ . '/output.txt', 'w'],
2 => ['file', __DIR__ . '/error.txt', 'w']],
$pipes,
__DIR__
);
if ($process === false) { throw new RuntimeException('Cannot start worker'); }
echo proc_close($process), "\n";
try { proc_close($process); }
catch (TypeError $error) { echo "Already closed\n"; }
Ожидаемый результат
4
Already closed
Правильная структура владеет одним закрытием. Нельзя «на всякий случай» вызывать proc_close из разных слоёв без согласования владения.
proc_close не устанавливает таймаут. Если worker завис, ждать можно долго. Не закрывайте выход, не прочитав требуемые данные: потеря данных и реакция ребёнка на закрытый канал зависят от программы. Завершение по deadline и ожидание его подтверждения — отдельная обязанность управляющего кода.
Следующий шаг: proc_open; proc_get_status; proc_terminate.
proc_get_statusУзнать, работает ли ваш дочерний процесс, и сохранить сведения о его завершении.
PHP 8.2+; изменения отмечены в тексте · standard
proc_get_status(resource $process): arrayУзнать, работает ли ваш дочерний процесс, и сохранить сведения о его завершении.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| process | Ресурс от proc_open, ещё не закрытый proc_close. |
| command / pid | Строка команды и целочисленный PID. Не выводите команду с секретами в публичную диагностику. |
| running | true пока процесс выполняется, false после завершения. Снимок может устареть сразу после чтения. |
| exitcode / cached | exitcode имеет смысл для завершённого процесса; -1 не означает обычный успех. PHP 8.3+ сохраняет код, cached сообщает о кэшировании. До 8.3 повторный запрос мог потерять код. |
| signaled / termsig | Был ли процесс завершён неперехваченным сигналом; номер сигнала значим лишь при signaled=true. Windows signaled всегда false. |
| stopped / stopsig | Был ли процесс приостановлен сигналом и каким. Windows stopped всегда false. Это не то же самое, что нормальное завершение. |
- Есть ресурс нашего worker
- Снимок status сообщает running
- После завершения читаем exitcode=4
- В PHP 8.3+ повторное чтение не теряет код
Файл worker.php
<?php echo "ready"; exit(4);Файл input.txt
<?php
declare(strict_types=1);
$process = proc_open(
[PHP_BINARY, '-n', __DIR__ . '/worker.php'],
[0 => ['file', __DIR__ . '/input.txt', 'r'],
1 => ['file', __DIR__ . '/output.txt', 'w'],
2 => ['file', __DIR__ . '/error.txt', 'w']],
$pipes,
__DIR__
);
if ($process === false) { throw new RuntimeException('Cannot start worker'); }
$deadline = microtime(true) + 3;
do {
$status = proc_get_status($process);
if (!$status['running']) { break; }
usleep(1000);
} while (microtime(true) < $deadline);
if ($status['running']) {
proc_terminate($process);
proc_close($process);
throw new RuntimeException('Fixture exceeded deadline');
}
echo $status['exitcode'], "\n";
echo proc_close($process), "\n";
Ожидаемый результат
4
4
Опрос делает паузу, а не занимает ядро бесконечным busy loop. Трёхсекундный deadline относится к собственному короткому fixture; это не переносимый production supervisor.
Файл worker.php
<?php echo "ready"; exit(4);Файл input.txt
<?php
declare(strict_types=1);
$process = proc_open(
[PHP_BINARY, '-n', __DIR__ . '/worker.php'],
[0 => ['file', __DIR__ . '/input.txt', 'r'],
1 => ['file', __DIR__ . '/output.txt', 'w'],
2 => ['file', __DIR__ . '/error.txt', 'w']],
$pipes,
__DIR__
);
if ($process === false) { throw new RuntimeException('Cannot start worker'); }
$deadline = microtime(true) + 3;
do {
$status = proc_get_status($process);
if (!$status['running']) { break; }
usleep(1000);
} while (microtime(true) < $deadline);
if ($status['running']) {
proc_terminate($process);
proc_close($process);
throw new RuntimeException('Fixture exceeded deadline');
}
$again = proc_get_status($process);
echo $again['exitcode'], "\n";
echo array_key_exists('cached', $again) ? "cached field exists\n" : "old PHP\n";
echo proc_close($process), "\n";
Ожидаемый результат
4
cached field exists
4
Проверяется PHP 8.3+. Исторический совет никогда не вызывать proc_get_status перед proc_close не описывает современный контракт. Точные моменты running/cached не привязываются к скорости компьютера.
Следующий шаг: proc_open; proc_close; proc_terminate.
proc_terminateПопросить завершиться именно тому процессу, которым владеет ваш запуск.
PHP 8.2+; изменения отмечены в тексте · standard
proc_terminate(resource $process, int $signal = 15): boolПопросить завершиться именно тому процессу, которым владеет ваш запуск.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| process | Ресурс собственного proc_open; не поиск произвольных процессов по имени. |
| signal | На POSIX номер отправляемого сигнала, по умолчанию 15 (SIGTERM). На Windows этот параметр не задаёт POSIX-сигнал. |
| Возврат | Булев результат отправки запроса завершения/системной операции; это не exit code и не доказательство, что процесс уже остановился. |
| Ожидание | Возвращается сразу. Далее проверяют статус, завершают работу с каналами и вызывают proc_close. |
| Границы | Завершение родителя-shell не означает остановку всех его потомков. Массив argv убирает лишний shell, но универсальный контроль дерева процессов всё равно требует платформенного supervisor. |
- worker подтвердил ready
- PHP вызвал proc_terminate
- Системный запрос принят либо отвергнут
- PHP закрывает свои каналы и ждёт подтверждения через proc_close
Файл worker.php
<?php echo "ready\n"; fflush(STDOUT); stream_get_contents(STDIN);<?php
declare(strict_types=1);
$process = proc_open(
[PHP_BINARY, '-n', __DIR__ . '/worker.php'],
[0 => ['pipe', 'r'], 1 => ['pipe', 'w'],
2 => ['file', __DIR__ . '/error.txt', 'w']],
$pipes, __DIR__
);
if ($process === false) { throw new RuntimeException('Cannot start worker'); }
$ready = fgets($pipes[1]);
if (trim($ready) !== 'ready') { throw new RuntimeException('Missing readiness'); }
$requested = proc_terminate($process);
fclose($pipes[0]);
fclose($pipes[1]);
$exitCode = proc_close($process);
var_dump($requested);
echo is_int($exitCode) ? "Process reaped\n" : "Unexpected\n";
Ожидаемый результат
bool(true)
Process reaped
Ребёнок создан именно этим примером и ждёт только собственного stdin. На POSIX/Windows код принудительного завершения может различаться, поэтому его конкретное число не обещается. Закрытие stdin также позволяет этому ограниченному worker завершиться самостоятельно.
Файл worker.php
<?php echo "ready\n"; fflush(STDOUT); stream_get_contents(STDIN);<?php
declare(strict_types=1);
$process = proc_open(
[PHP_BINARY, '-n', __DIR__ . '/worker.php'],
[0 => ['pipe', 'r'], 1 => ['pipe', 'w'],
2 => ['file', __DIR__ . '/error.txt', 'w']],
$pipes, __DIR__
);
if ($process === false) { throw new RuntimeException('Cannot start worker'); }
$ready = fgets($pipes[1]);
if (trim($ready) !== 'ready') { throw new RuntimeException('Missing readiness'); }
$reason = 'user_cancelled';
$requested = proc_terminate($process, 15);
fclose($pipes[0]);
fclose($pipes[1]);
$exitCode = proc_close($process);
echo $reason, "\n";
echo $requested ? "Stop requested\n" : "Stop request failed\n";
Ожидаемый результат
user_cancelled
Stop requested
В интерфейсе задаче сохраняют явную причину отмены. Не пытаются угадать user_cancelled по случайному системному числу. 15 имеет смысл сигнала только на POSIX; в Windows используется системное завершение.
SIGTERM можно перехватить/игнорировать на POSIX; принятие запроса не гарантирует быстрый выход. Принудительное завершение может оборвать запись файла и не выполнить finally ребёнка. Сначала проектируют безопасный протокол отмены и атомарную публикацию результата, затем ограниченное ожидание и политику принудительного завершения.
Следующий шаг: proc_get_status; proc_close; proc_open.
proc_niceИзменить приоритет текущего PHP-процесса, например отдельного фонового worker.
PHP 8.2+; изменения отмечены в тексте · standard
proc_nice(int $priority): boolИзменить приоритет текущего PHP-процесса, например отдельного фонового worker.
Здесь PHP обращается к операционной системе и запускает отдельную программу. Это не вызов PHP-функции внутри того же процесса. Знак $ начинает имя переменной, = сохраняет значение, а имя со скобками вызывает функцию. В скобках аргументы разделены запятыми; точка . склеивает строки. echo выводит текст, "\n" переводит строку. var_dump показывает также тип значения. В примерах PHP_BINARY — путь к текущему PHP CLI, __DIR__ — каталог самого примера.
Проверка === false отличает отказ от пустой строки и нуля. if выполняет блок при выполнении условия. throw new RuntimeException прекращает обычный путь при неожиданном отказе; try/finally гарантирует завершающие действия. Файлы worker.php ниже — собственные короткие дочерние программы: раскройте их содержимое и сохраните рядом с example.php либо скачайте весь пример. Пошаговая практическая глава о PHP, Python и Node.js.
Квадратные скобки [] создают массив, а запись 0 => значение связывает ключ с данными. foreach ($items as $item) по очереди берёт элементы; для коротких проверок ниже их заранее всего два или три. catch принимает ожидаемое исключение, чтобы показать понятный результат отказа. Запись условие ? A : B выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.
| Часть вызова | Значение и границы |
|---|---|
| priority на Unix | Прибавка к текущему nice. Положительная снижает приоритет, отрицательная повышает и обычно требует прав. Повторный вызов может ещё раз изменить nice. |
| priority на Windows | Выбирает класс приоритета текущего процесса, а не добавляет Unix nice. Доступно с PHP 7.2; точные диапазоны показаны в таблице главы. |
| Возврат / отказ | true при успехе, false и E_WARNING при отказе, в частности нехватке прав. Наличие зависит от возможностей системы/сборки. |
| Область действия | Это текущий процесс, не resource от proc_open. В Windows меняется приоритет всего процесса даже у thread-safe PHP. Не применять бездумно внутри общего веб-процесса. |
- Отдельный CLI worker уже запущен
- proc_nice снижает его приоритет
- Планировщик ОС чаще выбирает более приоритетные задачи при конкуренции
- Объём работы и права доступа не изменились
<?php
declare(strict_types=1);
if (!function_exists('proc_nice')) { throw new RuntimeException('Unsupported environment'); }
var_dump(proc_nice(0));
Ожидаемый результат
bool(true)
В проверенном Windows-процессе устанавливается нормальный класс. На Unix нулевая прибавка оставляет nice прежним. Этот пример — самостоятельный процесс, не запрос общего PHP-FPM/Apache worker.
<?php
declare(strict_types=1);
if (!function_exists('proc_nice')) { throw new RuntimeException('Unsupported environment'); }
if (!proc_nice(10)) { throw new RuntimeException('Priority was not changed'); }
echo "Background worker configured\n";
$total = 1200 + 800;
echo $total, "\n";
Ожидаемый результат
Background worker configured
2000
В Windows выбран Idle, на Unix nice увеличивается на 10. Самостоятельный CLI завершается, так что настройки не переходят к следующему веб-запросу. Это не ограничитель CPU/RAM, не пауза и не гарантия времени выполнения.
Для запуска с лимитами CPU/RAM и общей политикой очереди используйте возможности службы/supervisor/контейнера. Повышение приоритета не исправляет неэффективный алгоритм; измерьте длительность и стоимость самой работы. proc_nice не относится к ресурсу proc_open и не выбирает процесс по PID.
Следующий шаг: proc_open; proc_get_status.
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


