nick4fake / react-child-process
Requires
- php: >=5.3.0
- evenement/evenement: ^2.0 || ^1.0
- react/event-loop: ^0.4 || ^0.3
- react/stream: ^0.5 || ^0.4.4
Requires (Dev)
- phpunit/phpunit: ^5.0 || ^4.8.10
- sebastian/environment: ~1.0
This package is not auto-updated.
Last update: 2019-02-20 19:13:32 UTC
README
执行子进程的库。
该库将程序执行与事件循环集成。启动的子进程可以被信号,并在终止时发出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
许可
麻省理工学院,参见许可证文件。