W3docs

pclose()

Функция PHP pclose() закрывает указатель на процесс, открытый функцией popen(), и возвращает код завершения процесса.

Функция PHP pclose()

Функция PHP pclose() закрывает указатель на процесс — специальный поток, возвращаемый функцией popen() при запуске внешней команды. В отличие от fclose(), которая просто закрывает обычный файловый дескриптор, pclose() делает кое-что дополнительное: ожидает завершения дочернего процесса и возвращает его код завершения.

На этой странице рассматриваются синтаксис, возвращаемое значение (с одним важным нюансом), полный пример чтения и закрытия, а также когда стоит использовать proc_open() вместо pclose().

Зачем нужна pclose()

popen() запускает команду оболочки и предоставляет вам канал для передачи ввода ('w'-режим) или чтения вывода ('r'-режим). Этот канал поддерживается реальным процессом ОС. Если просто оставить дескриптор открытым — или закрыть его неправильной функцией — процесс может остаться зомби, а его код завершения будет потерян. pclose() является правильным аналогом: она сбрасывает буфер канала, блокирует выполнение до завершения дочернего процесса, освобождает его ресурсы и возвращает код завершения, чтобы скрипт мог реагировать на успех или ошибку.

Всегда используйте popen() и pclose() в паре. Использование fclose() для дескриптора, полученного от popen(), является неопределённым поведением.

Синтаксис

pclose(resource $handle): int

Параметры

Функция принимает один параметр:

  • $handle — указатель на процесс, возвращённый функцией popen(). Передача ресурса другого типа является недопустимой.

Возвращаемое значение

pclose() возвращает статус завершения процесса в виде целого числа (это исходное значение из C-функции pclose — на большинстве систем фактический код завершения хранится в старшем байте). Функция возвращает -1, если процесс не удалось завершить корректно. В старых версиях PHP передача некорректного дескриптора вызывает предупреждение и возвращает FALSE.

Чтобы получить обычный код завершения в Unix-подобных системах, сдвиньте значение вправо на 8 бит:

$status   = pclose($handle);
$exitCode = $status >> 8;   // 0 means the command succeeded

Пример

Откройте команду, прочитайте её вывод, затем закройте канал и проверьте результат:

<?php

// Run an external command and read its output.
$handle = popen('ls -la', 'r');

if ($handle === false) {
    die("Failed to start the command.\n");
}

$output = '';
while (!feof($handle)) {
    $output .= fread($handle, 1024);
}

echo $output;

// Close the pipe and capture the process exit status.
$status   = pclose($handle);
$exitCode = $status >> 8;

echo "Command exited with code: $exitCode\n";

Мы открываем указатель на процесс с помощью popen(), читаем весь вывод в цикле с помощью fread() (один вызов fread может не захватить всё при большом объёме вывода), затем закрываем канал с помощью pclose() и декодируем код завершения. Код завершения 0 по соглашению означает успех.

Распространённые ошибки

  • Не путайте fclose() и pclose(). Дескриптор от popen() должен закрываться через pclose(), а дескриптор от fopen() — через fclose().
  • pclose() блокирует выполнение. Функция ожидает завершения дочернего процесса. Если команда никогда не завершится, скрипт зависнет.
  • Читайте перед закрытием. pclose() может отбросить не прочитанный буферизованный вывод, поэтому сначала завершите чтение канала.
  • Один канал — одно направление. Канал popen() является либо читаемым, либо записываемым, но не обоими сразу — для двунаправленного взаимодействия используйте proc_open().

Когда использовать proc_open()

popen()/pclose() отлично подходят для быстрой одноразовой команды, когда нужен только её вывод или ввод данных в неё. Когда необходимы оба направления одновременно, раздельные stdout и stderr, управление окружением или рабочим каталогом — используйте proc_open(), которая предоставляет полный двунаправленный контроль над запущенным процессом.

Заключение

pclose() является обязательным компаньоном функции popen(): она закрывает канал процесса, ожидает завершения команды и возвращает её код завершения, чтобы можно было проверить успешность выполнения. Всегда используйте эти функции в паре, читайте канал перед закрытием и не забывайте сдвигать статус вправо на 8 бит для получения реального кода завершения в Unix-системах. Для всего, что выходит за рамки однонаправленного канала, используйте proc_open().

Practice

Практика
Какова роль функции pclose() в PHP?
Какова роль функции pclose() в PHP?
Was this page helpful?