Proc close: примеры (PHP)

Функция proc_close в PHP: полное руководство с практическими примерами
Раздел: Процессы
proc_close(resource $process): int

Функция proc_close в PHP

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

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

Функция принимает один обязательный аргумент:

  • $process – ресурс типа process, возвращаемый функцией proc_open(). Этот ресурс представляет запущенный внешний процесс.

Возвращаемое значение – целое число, представляющее код завершения процесса. В случае ошибки возвращается -1.

Когда используется

Функция применяется в сценариях, требующих взаимодействия с внешними программами: обработка данных специализированными утилитами, управление системными службами, параллельное выполнение задач. Основное назначение – корректное завершение процесса после завершения обмена данными.

Примеры использования proc_close

Базовый пример запуска и завершения процесса
<?
$descriptors = [
    0 => ["pipe", "r"], // stdin
    1 => ["pipe", "w"], // stdout
    2 => ["pipe", "w"]  // stderr
];

$process = proc_open('echo "Тестовый вывод"', $descriptors, $pipes);

if (is_resource($process)) {
    fclose($pipes[0]);
    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    fclose($pipes[2]);
    
    $return_value = proc_close($process);
    echo "Код завершения: " . $return_value;
}
?>
Тестовый вывод
Код завершения: 0
Пример с обработкой ошибок
<?
$process = proc_open('несуществующая_команда', [], $pipes);

if (is_resource($process)) {
    $return_value = proc_close($process);
    echo "Код: " . $return_value;
} else {
    echo "Не удалось запустить процесс";
}
?>
Код: -1

Альтернативные функции в PHP

shell_exec()

Выполняет команду через оболочку и возвращает вывод в виде строки. Подходит для простых задач без необходимости управления вводом-выводом.

exec()

Выполняет внешнюю программу и возвращает последнюю строку вывода. Позволяет получить полный вывод в массив и код возврата.

system()

Выполняет внешнюю команду и выводит результат непосредственно в браузер. Возвращает последнюю строку вывода.

popen()/pclose()

Открывает процесс для односторонней передачи данных (только чтение или только запись). Не обеспечивает такого же уровня контроля, как proc_open().

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

Python: subprocess.run()
import subprocess
result = subprocess.run(['echo', 'Тестовый вывод'], 
                       capture_output=True, text=True)
print(result.stdout)
print(f"Код завершения: {result.returncode}")
Тестовый вывод
Код завершения: 0
JavaScript (Node.js): child_process.spawn()
const { spawn } = require('child_process');
const process = spawn('echo', ['Тестовый вывод']);

process.stdout.on('data', (data) => {
    console.log(data.toString());
});

process.on('close', (code) => {
    console.log(`Код завершения: ${code}`);
});
Тестовый вывод
Код завершения: 0
Bash: запуск с получением кода возврата
echo "Тестовый вывод"
echo "Код завершения: $?"
Тестовый вывод
Код завершения: 0

Типичные ошибки при использовании

Закрытие каналов до proc_close()
<?
$descriptors = [
    0 => ["pipe", "r"],
    1 => ["pipe", "w"]
];

$process = proc_open('sleep 5', $descriptors, $pipes);

fclose($pipes[0]);
// Не закрыт $pipes[1] перед proc_close()
$return_value = proc_close($process);
?>

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

Попытка повторного вызова proc_close()
<?
$process = proc_open('echo test', [], $pipes);
proc_close($process);
$result = proc_close($process); // Второй вызов
var_dump($result);
?>
Warning: proc_close(): supplied resource is not a valid stream resource
int(-1)
Использование некорректного ресурса
<?
$fp = fopen('file.txt', 'r');
$result = proc_close($fp); // Передача ресурса файла
?>
Warning: proc_close(): supplied resource is not a valid stream resource

Изменения в последних версиях PHP

PHP 8.0.0

Функция теперь выбрасывает исключение TypeError при передаче аргумента нересурсного типа. Ранее выдавалось предупреждение и возвращалось значение null.

<?
// PHP 8+
try {
    proc_close(null);
} catch (TypeError $e) {
    echo "Ошибка типа: " . $e->getMessage();
}
?>
Ошибка типа: proc_close(): supplied resource is not a valid stream resource
PHP 7.4.0

Улучшена обработка процессов в Windows, исправлены проблемы с блокировкой при чтении/записи.

Расширенные примеры использования

Асинхронное выполнение с обработкой stdout и stderr
Пример php
<?
$descriptors = [
    0 => ["pipe", "r"],
    1 => ["pipe", "w"],
    2 => ["pipe", "w"]
];

$process = proc_open(
    'find /var/www -name "*.php" 2>&1',
    $descriptors,
    $pipes,
    null,
    null,
    ['bypass_shell' => true]
);

if (is_resource($process)) {
    fclose($pipes[0]);
    
    stream_set_blocking($pipes[1], false);
    stream_set_blocking($pipes[2], false);
    
    $stdout = '';
    $stderr = '';
    $running = true;
    
    while ($running) {
        $read = [$pipes[1], $pipes[2]];
        $write = null;
        $except = null;
        
        if (stream_select($read, $write, $except, 0, 200000) !== false) {
            foreach ($read as $stream) {
                if ($stream === $pipes[1]) {
                    $stdout .= stream_get_contents($stream);
                } else {
                    $stderr .= stream_get_contents($stream);
                }
            }
        }
        
        $status = proc_get_status($process);
        $running = $status['running'];
    }
    
    fclose($pipes[1]);
    fclose($pipes[2]);
    
    $return_value = proc_close($process);
    
    echo "STDOUT: " . substr($stdout, 0, 200) . "...\n";
    echo "STDERR: " . $stderr . "\n";
    echo "Код возврата: " . $return_value;
}
?>
Взаимодействие с интерактивной программой
Пример php
<?
$descriptors = [
    0 => ["pipe", "r"],
    1 => ["pipe", "w"],
    2 => ["pipe", "w"]
];

$process = proc_open(
    'bc -q',
    $descriptors,
    $pipes
);

if (is_resource($process)) {
    fwrite($pipes[0], "2 + 2 * 2\n");
    fwrite($pipes[0], "quit\n");
    fclose($pipes[0]);
    
    $output = stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    fclose($pipes[2]);
    
    $return_value = proc_close($process);
    
    echo "Результат вычислений: " . $output;
}
?>
Результат вычислений: 6
Запуск с разными рабочими директориями и переменными окружения
Пример php
<?
$descriptors = [
    1 => ["pipe", "w"],
    2 => ["pipe", "w"]
];

$cwd = '/tmp';
$env = ['CUSTOM_VAR' => 'test_value'];

$process = proc_open(
    'echo $CUSTOM_VAR && pwd',
    $descriptors,
    $pipes,
    $cwd,
    $env
);

if (is_resource($process)) {
    $output = stream_get_contents($pipes[1]);
    $errors = stream_get_contents($pipes[2]);
    
    fclose($pipes[1]);
    fclose($pipes[2]);
    
    proc_close($process);
    
    echo $output;
}
?>
test_value
/tmp

PHP proc_close function comments

En
Proc close Close a process opened by proc_open and return the exit code of that process