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

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

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

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

Глава 90 · От основ к практике

Запуск программ: полный справочник, вывод и управление процессом

Как PHP вызывает Python/Node/CLI, принимает данные и ошибки, ждёт завершения и избегает путаницы shell, argv и pipe.

Есть готовый обработчик на Python: как передать ему работу из PHP

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

От PHP-задания до проверенного результата

Worker считает отчёт по заказам. Одного непустого текста недостаточно: родитель проверяет завершение и формат ответа.

  1. PHP → worker

    Известная программа получает отдельные аргументы и данные stdin. Переменные PHP не становятся общими переменными другого языка.

  2. stdout: total=9000

    Канал полезного результата. Может содержать только часть ответа при отказе.

  3. stderr и 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 выбирает одно из двух значений. Массивы, условия и циклы и исключения разобраны отдельно от процесса.

Что реально появляется при запуске
  1. Родитель PHP хранит переменные задания
  2. ОС создаёт отдельный процесс worker
  3. worker получает аргументы/входной поток, а не переменные PHP напрямую
  4. Родитель получает вывод и статус, проверяет их и продолжает

Чтобы увидеть механизм без установки 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 исходя из того, какие из них нужны вашему приложению.

Пример отчёта
  1. stdout: total=9000 — данные
  2. stderr: processed=2 — техническая запись
  3. exit: 0 — договор об успехе
  4. 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, рабочий каталог и доступ к файлам.

От HTTP-запроса до разрешения ОС
  1. PHP-процесс имеет конкретного системного пользователя
  2. Конфигурация могла отключить функцию
  3. ОС проверяет путь и права на программу/файлы
  4. Дочерняя программа работает с этими ограничениями
Проверить функции в текущем CLIСамостоятельный пример
<?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 там не разбирает амперсанд как командный оператор.

Разделённый договор
  1. Доверенный абсолютный путь: какой исполняемый файл
  2. Фиксированная операция и проверенные отдельные аргументы
  3. Большие/сложные данные: stdin, например JSON
  4. Программа сама проверяет схему, диапазоны и допустимые опции

Не смешивайте HTML-экранирование и shell-экранирование. htmlspecialchars нужен перед выводом в HTML, escapeshellarg — только при формировании отдельного аргумента shell. Оба не нужны для элемента argv-массива. Программная опция --delete не становится допустимой лишь оттого, что передана одним аргументом.

Файл input.txt
Файл worker.php
<?php echo $argv[1];
Передать специальные символы без shellСамостоятельный пример
<?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 для всех случаев.

Взаимное ожидание
  1. PHP заполняет stdin и ждёт, когда ребёнок прочитает
  2. worker заполняет stdout и ждёт, когда PHP прочитает
  3. PHP ещё занят записью stdin
  4. worker ещё занят записью stdout → оба ждут
СитуацияРабочая стратегия
Короткий известный запрос и короткий ответПростейший последовательный обмен допустим при строгой границе объёма и поведении worker. Закройте stdin после записи.
Большие двусторонние потоки POSIXНеблокирующий цикл с одновременным обслуживанием stdin/stdout/stderr, учётом частичных записей, deadline и ограничений объёма.
Windows proc_open pipesНельзя механически перенести POSIX stream_select: он не поддерживает эти дескрипторы так же. Используйте проверенный process runner/платформенный supervisor или файловый протокол.
Разовый отчёт через файлыСобственный каталог задания отделяет вход и оба выхода; нужны квоты, срок жизни, проверка ошибок диска и атомарная публикация.

Маленькие примеры показывают конкретный вызов, а файловый runner с JSON связывает его с отчётом. Файлы устраняют именно взаимное заполнение pipe, но не дают бесплатный timeout и не ограничивают диск. Нужны также обработка исчезнувшей программы и проверка формата результата.

Код завершения, отмена, приоритет и стоимость

Управляемое задание
  1. Создать ID и известный вход
  2. Запустить и наблюдать до deadline
  3. При отказе/отмене остановить, затем подтвердить завершение
  4. Принять проверенный результат либо сохранить понятную причину отказа

Нельзя обещать, что proc_terminate остановит всё дерево процессов: shell/worker могут породить потомков. Для сервиса с несколькими пользователями задачу выносят в очередь и процесс под управлением supervisor, а HTTP возвращает ID и статус. Повторный запуск должен учитывать идемпотентность и уже созданные файлы.

Запуск отдельного процесса добавляет создание процесса, загрузку программы, передачу данных и переключение контекста. Для маленькой операции это может быть дороже самой работы. Не называйте exec быстрее system без измерения одинаковой задачи. Приоритет влияет на планирование при конкуренции, а не уменьшает число вычислений.

proc_nice: Windows 8.5.11Класс текущего процесса
-10 и меньшеHigh
-9…-5Above normal
-4…4Normal
5…9Below 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 здесь недостаточно.

Критерий решения
  1. Есть непустой stdout checked=2
  2. Есть exit code 4
  3. Оба результата принадлежат одному запуску
  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.
Вывод и return — разные каналы
  1. worker пишет две строки
  2. system отправляет обе в вывод PHP
  3. last сохраняет только total=9000
  4. Дополнительный echo last повторил бы последнюю строку
Файл worker.php
<?php
echo "rows=2\n";
echo "total=9000\n";
Показать отчёт без лишнего echo systemСамостоятельный пример
<?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>
";
Перехватить вывод перед показом в HTMLСамостоятельный пример
<?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');
Ожидаемый результат
&lt;b&gt;report&lt;/b&gt;

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.

Следующий шаг: exec; passthru; proc_open.

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.
HTTPContent-Type и остальные заголовки задают до тела ответа. Уже переданные повреждённые/частичные данные нельзя отозвать после неуспеха конвертера. Если нужен атомарный ответ, сначала получите и проверьте результат.
Бинарный вывод
  1. worker пишет байты A, NUL, B
  2. passthru передаёт их в буфер PHP
  3. hex показывает 410042 без потери NUL
  4. Возврат 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.

Следующий шаг: system; exec; proc_open.

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. Здесь используется явная функция.
Собрать текст целиком
  1. worker печатает две строки
  2. shell ждёт завершения
  3. shell_exec возвращает одну строку с переводами строк
  4. Кода завершения в возвращаемом значении нет
Файл 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);
Понять, почему null недостаточно для проверки заданияСамостоятельный пример
<?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.

Следующий шаг: exec; proc_open; passthru.

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; лимиты длины задаются реализацией/ОС. Это не способ обхода запрета запуска и не проверка допустимых опций программы.
Один аргумент с пробелом
  1. Текст monthly report
  2. escapeshellarg добавляет системные кавычки
  3. shell передаёт worker один элемент argv
  4. 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: нежелательные опции могут остаться отдельными аргументами.
Почему cmd и arg различаются
  1. Вход содержит monthly report
  2. escapeshellcmd оставляет пробел разделителем
  3. При подстановке получатся два слова
  4. 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.
Завершение задания
  1. proc_open создал ресурс
  2. worker записал ready и завершился с 4
  3. proc_close дождался и вернул 4
  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. Не выводите команду с секретами в публичную диагностику.
runningtrue пока процесс выполняется, false после завершения. Снимок может устареть сразу после чтения.
exitcode / cachedexitcode имеет смысл для завершённого процесса; -1 не означает обычный успех. PHP 8.3+ сохраняет код, cached сообщает о кэшировании. До 8.3 повторный запрос мог потерять код.
signaled / termsigБыл ли процесс завершён неперехваченным сигналом; номер сигнала значим лишь при signaled=true. Windows signaled всегда false.
stopped / stopsigБыл ли процесс приостановлен сигналом и каким. Windows stopped всегда false. Это не то же самое, что нормальное завершение.
Наблюдение без ожидания
  1. Есть ресурс нашего worker
  2. Снимок status сообщает running
  3. После завершения читаем exitcode=4
  4. В PHP 8.3+ повторное чтение не теряет код
Файл worker.php
<?php echo "ready"; exit(4);
Файл input.txt
Дождаться короткого worker с ограниченным опросомСамостоятельный пример
<?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.
Отмена отдельного задания
  1. worker подтвердил ready
  2. PHP вызвал proc_terminate
  3. Системный запрос принят либо отвергнут
  4. PHP закрывает свои каналы и ждёт подтверждения через proc_close
Файл worker.php
<?php echo "ready\n"; fflush(STDOUT); stream_get_contents(STDIN);
Остановить собственный ожидающий workerСамостоятельный пример
<?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);
Отделить причину отмены задания от системного exit codeСамостоятельный пример
<?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. Не применять бездумно внутри общего веб-процесса.
Приоритет фонового отчёта
  1. Отдельный CLI worker уже запущен
  2. proc_nice снижает его приоритет
  3. Планировщик ОС чаще выбирает более приоритетные задачи при конкуренции
  4. Объём работы и права доступа не изменились
Проверить доступность изменения приоритета в отдельном CLIСамостоятельный пример
<?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.

Понизить приоритет самостоятельного отчётного 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. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.