nick4fake/react-child-process

该软件包已被弃用且不再维护。作者建议使用nick4fake/react-child-process软件包。

执行子进程的库。

v0.4.3 2017-03-14 13:23 UTC

This package is not auto-updated.

Last update: 2019-02-20 19:13:32 UTC


README

Build Status Code Climate

执行子进程的库。

该库将程序执行事件循环集成。启动的子进程可以被信号,并在终止时发出exit事件。此外,进程I/O流(即STDIN、STDOUT、STDERR)作为暴露。

目录

快速入门示例

$loop = React\EventLoop\Factory::create();

$process = new React\ChildProcess\Process('echo foo');
$process->start($loop);

$process->stdout->on('data', function ($chunk) {
    echo $chunk;
});

$process->on('exit', function($exitCode, $termSignal) {
    echo 'Process exited with code ' . $exitCode . PHP_EOL;
});

$loop->run();

也请参阅示例

进程

EventEmitter事件

  • exit:每当进程不再运行时都会发出。事件监听器将接收退出代码和终止信号作为两个参数。

方法

  • start():启动进程并将其I/O流注册到事件循环。stdin流将保持暂停状态。
  • terminate():向进程发送信号(默认为SIGTERM)。

Process类还有其他公共方法,可以用来访问通过proc_get_status()字段无法访问的字段。

流属性

一旦启动进程,其I/O流将构建为React\Stream\Stream的实例。在调用start()之前,这些属性为null。一旦进程终止,流将关闭但不会未设置。

  • $stdin
  • $stdout
  • $stderr

这些中的每一个都实现了底层的DuplexStreamInterface,您可以使用其任何事件和方法,就像平常一样。

$process->stdout->on('data', function ($chunk) {
    echo $chunk;
});

$process->stdout->on('end', function () {
    echo 'ended';
});

$process->stdout->on('error', function (Exception $e) {
    echo 'error: ' . $e->getMessage();
});

$process->stdout->on('close', function () {
    echo 'closed';
});

$process->stdin->write($data);
$process->stdin->end($data = null);
$process->stdin->close();
//

有关更多详细信息,请参阅DuplexStreamInterface

命令

Process类允许您传递任何类型的命令行字符串。

$process = new Process('echo test');

默认情况下,PHP将通过将给定的命令行字符串包装在sh命令中启动进程,因此上述示例实际上会在幕后执行sh -c echo test

这是一个非常有用的功能,因为它不仅允许您传递单个命令,而且还允许您传递任何类型的shell命令行,并使用命令链(使用&&||;等)启动多个子命令,并允许您重定向STDIO流(使用2>&1等)。这可以用来传递完整的命令行并从包装的shell命令接收结果STDIO流,如下所示:

$process = new Process('echo run && demo || echo failed');

换句话说,底层shell负责管理这个命令行并启动各个子命令,以及根据需要连接它们的STDIO流。这意味着Process类只会从包装shell接收结果的STDIO流,因此将包含完整的输入/输出,无法区分单个子命令的输入/输出。

如果您想区分单个子命令的输出,您可能需要实现一些高级协议逻辑,例如像这样在每个子命令之间打印一个显式的边界

$process = new Process('cat first && echo --- && cat second');

作为替代方案,考虑一次启动一个进程并监听其exit事件,以有条件地启动链中的下一个进程。这将为您提供配置后续进程I/O流的机会

$first = new Process('cat first');
$first->start($loop);

$first->on('exit', function () use ($loop) {
    $second = new Process('cat second');
    $second->start($loop);
});

请注意,PHP使用shell包装器处理所有命令行。虽然这看起来对于更复杂的命令行似乎是合理的,但实际上这也适用于运行最简单的单个命令

$process = new Process('yes');

这实际上会生成一个类似于以下的命令层次结构

5480 … \_ php example.php
5481 …    \_ sh -c yes
5482 …        \_ yes

这意味着尝试获取底层进程PID或发送信号实际上会针对包装shell,这在许多情况下可能不是期望的结果。

如果您不希望出现这个包装shell进程,只需在命令字符串前加上exec即可,这将导致包装shell进程被我们的进程替换

$process = new Process('exec yes');

这将显示一个类似于以下的命令层次结构

5480 … \_ php example.php
5481 …    \_ yes

这意味着尝试获取底层进程PID和发送信号现在将针对预期的实际命令。

请注意,在这种情况下,命令行不会在包装shell中运行。这意味着当使用exec时,无法传递包含命令链或重定向STDIO流的命令行。

作为一个经验法则,大多数命令在包装shell中运行应该没问题。如果您传递完整的命令行(或不确定),您很可能需要保留包装shell。如果您只想传递单个命令,您可能需要考虑在命令字符串前加上exec以避免包装shell。

Sigchild 兼容性

当PHP通过--enabled-sigchild选项编译时,无法通过proc_close()proc_get_status()可靠地确定子进程的退出代码。相反,我们通过第四个管道执行子进程,并使用它来检索其退出代码。

此行为默认启用,仅在必要时使用。可以通过在Process启动之前调用setEnhanceSigchildCompatibility(false)来手动禁用此功能,在这种情况下,exit事件可能会收到null而不是实际的退出代码。

注意:此功能是从Symfony的Process组件中提取的。

安装

安装此库的推荐方法是通过Composer。您是Composer的新手吗?新到Composer?

这将安装最新支持的版本

$ composer require react/child-process:^0.4.3

有关版本升级的更多详细信息,请参阅CHANGELOG

测试

要运行测试套件,您首先需要克隆此仓库,然后通过Composer安装所有依赖项

$ composer install

要运行测试套件,请转到项目根目录并运行

$ php vendor/bin/phpunit

许可

麻省理工学院,参见许可证文件