Pclose: примеры (PHP)
pclose(resource $handle): intФункция 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Функция proc_close() закрывает процесс, открытый proc_open(), и возвращает код завершения. В отличие от pclose(), работает с более сложными конвейерами, позволяя управлять стандартными потоками ввода, вывода и ошибок отдельно.
Функция 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В 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
Код возврата: 0Pclose в 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 8.0 значительных изменений в работе функции pclose() не было. Однако, в ранних версиях, до PHP 5.0, функция могла вести себя иначе при обработке ошибок. В PHP 8 тип аргумента строго проверяется, и передача нересурса вызывает TypeError.
В PHP 8.1 улучшена совместимость с типами, но сигнатура функции осталась прежней: pclose(resource $handle): int.
Проверка успешности выполнения команды через код возврата.
$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Поочередная запись и чтение из процесса через два отдельных канала (эмулируется).
// Запись в процесс
$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Закрытие процесса, который выполняется длительное время, с таймаутом (через внешнее управление).
$handle = popen('sleep 10; echo done', 'r');
// Ждем 2 секунды, затем принудительно закрываем
sleep(2);
$status = pclose($handle);
echo "Процесс завершен с кодом: $status\n";Процесс завершен с кодом: 0Запуск нескольких процессов и их закрытие с сбором кодов возврата.
$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
)