Pclose: примеры (PHP)

Работа с pclose для управления процессами в PHP
Раздел: Процессы
pclose(resource $handle): int
Основы функции pclose

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

Использование функции необходимо после завершения работы с процессами, запущенными через popen(), чтобы избежать утечек ресурсов.

Аргументы функции

Функция принимает единственный аргумент:

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

Функция возвращает код завершения дочернего процесса. Если произошла ошибка, возвращается -1. Код возврата может использоваться для анализа успешности выполнения команды.

Простые примеры использования
Закрытие канала после чтения вывода

Чтение вывода команды и закрытие дескриптора.

$handle = popen('ls -la', 'r');
if ($handle) {
    echo fread($handle, 4096);
    $return_status = pclose($handle);
    echo "Код возврата: $return_status\n";
}
total 12
drwxr-xr-x 2 user user 4096 Apr 10 12:34 .
drwxr-xr-x 5 user user 4096 Apr 10 11:20 ..
-rw-r--r-- 1 user user   78 Apr 10 12:34 index.php
Код возврата: 0
Закрытие канала после записи

Передача данных в процесс и закрытие.

$handle = popen('cat > output.txt', 'w');
if ($handle) {
    fwrite($handle, "Hello, World!\n");
    $return_status = pclose($handle);
    echo "Код возврата: $return_status\n";
}
Код возврата: 0
Похожие функции в PHP

Функция proc_close() закрывает процесс, открытый proc_open(), и возвращает код завершения. В отличие от pclose(), работает с более сложными конвейерами, позволяя управлять стандартными потоками ввода, вывода и ошибок отдельно.

shell_exec

Функция shell_exec() выполняет команду через оболочку и возвращает вывод в виде строки. Удобна для простых задач, где не требуется интерактивное взаимодействие с процессом.

Выбор функции

pclose() используется вместе с popen() для простого однонаправленного взаимодействия. proc_close() предпочтительнее для сложных многопоточных операций. shell_exec() подходит для быстрого выполнения команд без управления каналами.

Аналоги в других языках

Pclose в Python

Модуль subprocess предоставляет функцию Popen.communicate() или закрытие через Popen.wait(). Процессы управляются более гибко.

import subprocess
proc = subprocess.Popen(['ls', '-la'], stdout=subprocess.PIPE)
output, error = proc.communicate()
print(output.decode())
print(f"Код возврата: {proc.returncode}")
total 12
drwxr-xr-x 2 user user 4096 Apr 10 12:34 .
drwxr-xr-x 5 user user 4096 Apr 10 11:20 ..
-rw-r--r-- 1 user user   78 Apr 10 12:34 index.py
Код возврата: 0
JavaScript (Node.js)

В Node.js используется модуль child_process. Метод spawn() создает процесс, а закрытие осуществляется автоматически или через kill().

const { spawn } = require('child_process');
const ls = spawn('ls', ['-la']);
ls.stdout.on('data', (data) => {
    console.log(data.toString());
});
ls.on('close', (code) => {
    console.log(`Код возврата: ${code}`);
});
total 12
drwxr-xr-x 2 user user 4096 Apr 10 12:34 .
drwxr-xr-x 5 user user 4096 Apr 10 11:20 ..
-rw-r--r-- 1 user user   78 Apr 10 12:34 index.js
Код возврата: 0

Pclose в MySQL

В MySQL нет прямой аналогии, так как это СУБД, а не язык для управления процессами. Однако можно использовать системные команды через sys_exec() в пользовательских функциях, но это требует специальных разрешений.

Типичные ошибки
Повторное закрытие дескриптора

Попытка закрыть уже закрытый дескриптор приводит к предупреждению.

$handle = popen('ls', 'r');
if ($handle) {
    pclose($handle);
    pclose($handle); // Ошибка
}
PHP Warning: pclose(): supplied resource is not a valid stream resource
Использование некорректного ресурса

Передача неверного значения в функцию вызывает ошибку.

$handle = null;
$status = pclose($handle); // Ошибка
PHP Warning: pclose() expects parameter 1 to be resource, null given
Игнорирование кода возврата

Не проверяется код завершения процесса, что может скрыть ошибки выполнения команды.

$handle = popen('command_that_fails', 'r');
echo fread($handle, 1024);
$status = pclose($handle); // Код возврата не равен 0, но игнорируется
Код возврата: 127
Изменения в версиях PHP

В PHP 8.0 значительных изменений в работе функции pclose() не было. Однако, в ранних версиях, до PHP 5.0, функция могла вести себя иначе при обработке ошибок. В PHP 8 тип аргумента строго проверяется, и передача нересурса вызывает TypeError.

В PHP 8.1 улучшена совместимость с типами, но сигнатура функции осталась прежней: pclose(resource $handle): int.

Расширенные примеры
Обработка ошибок с анализом кода возврата

Проверка успешности выполнения команды через код возврата.

Пример php
$handle = popen('grep -r "pattern" /some/dir 2>&1', 'r');
if ($handle) {
    $output = '';
    while (!feof($handle)) {
        $output .= fread($handle, 2048);
    }
    $return_status = pclose($handle);
    if ($return_status === 0) {
        echo "Поиск успешен:\n$output";
    } else {
        echo "Поиск завершился с ошибкой (код $return_status):\n$output";
    }
}
Поиск завершился с ошибкой (код 2):
grep: /some/dir: No such file or directory
Интерактивная работа с процессом

Поочередная запись и чтение из процесса через два отдельных канала (эмулируется).

Пример php
// Запись в процесс
$handle_write = popen('tee output.log', 'w');
if ($handle_write) {
    fwrite($handle_write, "Data line 1\n");
    fwrite($handle_write, "Data line 2\n");
    pclose($handle_write);
}
// Чтение из файла, в который записал tee
readfile('output.log');
Data line 1
Data line 2
Использование с long-running процессами

Закрытие процесса, который выполняется длительное время, с таймаутом (через внешнее управление).

Пример php
$handle = popen('sleep 10; echo done', 'r');
// Ждем 2 секунды, затем принудительно закрываем
sleep(2);
$status = pclose($handle);
echo "Процесс завершен с кодом: $status\n";
Процесс завершен с кодом: 0
Параллельное выполнение команд

Запуск нескольких процессов и их закрытие с сбором кодов возврата.

Пример php
$commands = ['whoami', 'date', 'uname -a'];
$handles = [];
foreach ($commands as $cmd) {
    $handles[$cmd] = popen($cmd, 'r');
}
$results = [];
foreach ($handles as $cmd => $handle) {
    $results[$cmd] = stream_get_contents($handle);
    $return_codes[$cmd] = pclose($handle);
}
print_r($results);
print_r($return_codes);
Array
(
    [whoami] => www-data
    [date] => Mon Apr 10 12:34:56 UTC 2023
    [uname -a] => Linux server 5.4.0-105-generic #119-Ubuntu SMP Mon Mar 7 18:49:24 UTC 2022 x86_64 GNU/Linux
)
Array
(
    [whoami] => 0
    [date] => 0
    [uname -a] => 0
)

PHP pclose function comments

En
Pclose Closes process file pointer