想象一下,你的 php 应用需要执行一个
git pull
ffmpeg
ls -la
exec()
shell_exec()
system()
exec()
shell_exec()
这些问题让我们的代码变得“野蛮生长”,难以管理。那么,有没有一种更优雅、更现代的方式来处理 PHP 中的外部命令执行呢?答案是肯定的,Composer 生态为我们提供了强大的解决方案。
ghostwriter/shell
首先登场的是
ghostwriter/shell
proc_open
安装 ghostwriter/shell
<pre class="brush:php;toolbar:false;">composer require ghostwriter/shell
基本用法:
立即学习“PHP免费学习笔记(深入)”;
ghostwriter/shell
Shell
execute
Result
<pre class="brush:php;toolbar:false;">use Ghostwriter\Shell\Shell;
use RuntimeException;
// 创建 Shell 实例
$shell = Shell::new();
// 切换到临时目录(示例,通常不推荐在Web应用中随意cd)
$shell->execute('cd', [sys_get_temp_dir()]);
// 执行一个 PHP 命令,打印 "#BlackLivesMatter"
$result = $shell->execute(PHP_BINARY, ['-r', 'echo "#BlackLivesMatter";']);
// 获取命令的退出码
$exitCode = $result->exitCode(); // 0 表示成功
if ($exitCode !== 0) {
// 如果退出码不为0,说明命令执行失败,可以获取标准错误输出
throw new RuntimeException($result->stderr());
}
if ($exitCode === 0) {
// 命令成功执行,获取标准输出
echo $result->stdout(); // 输出:#BlackLivesMatter
}通过
ghostwriter/shell
然而,
ghostwriter/shell
execute
guzzlehttp/promises
guzzlehttp/promises
guzzlehttp/promises
安装 guzzlehttp/promises
<pre class="brush:php;toolbar:false;">composer require guzzlehttp/promises
Promise 的核心概念:
Promise
pending
fulfilled
rejected
then(callable $onFulfilled, callable $onRejected)
$onFulfilled
$onRejected
then
resolve($value)
reject($reason)
pending
fulfilled
rejected
如何结合 ghostwriter/shell
guzzlehttp/promises
虽然
ghostwriter/shell
execute
示例:用 Promise 封装命令执行
<pre class="brush:php;toolbar:false;">use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\RejectedPromise;
use Ghostwriter\Shell\Shell;
use Exception;
function executeCommandAsync(array $commandAndArgs): Promise
{
return new Promise(function (callable $resolve, callable $reject) use ($commandAndArgs) {
// 在这里执行同步命令
$shell = Shell::new();
try {
$result = $shell->execute($commandAndArgs[0], array_slice($commandAndArgs, 1));
$exitCode = $result->exitCode();
if ($exitCode === 0) {
// 命令成功,解决 Promise
$resolve($result->stdout());
} else {
// 命令失败,拒绝 Promise
$reject(new Exception("Command failed with exit code {$exitCode}: " . $result->stderr()));
}
} catch (Exception $e) {
// 捕获执行过程中的异常
$reject($e);
}
});
}
echo "开始执行命令...\n";
// 封装一个成功的命令
$successPromise = executeCommandAsync([PHP_BINARY, '-r', 'echo "Hello from PHP script!";']);
$successPromise
->then(function ($output) {
echo "命令成功完成:\n" . $output . "\n";
return "处理后的结果:" . strtoupper($output); // 链式传递
})
->then(function ($processedOutput) {
echo $processedOutput . "\n";
})
->otherwise(function ($reason) { // 统一处理链中任何拒绝
echo "命令执行失败(成功链):" . $reason->getMessage() . "\n";
});
// 封装一个失败的命令 (例如,不存在的命令)
$failurePromise = executeCommandAsync(['non_existent_command', '-v']);
$failurePromise
->then(function ($output) {
echo "命令成功完成(失败链):\n" . $output . "\n";
})
->otherwise(function ($reason) {
echo "命令执行失败:\n" . $reason->getMessage() . "\n";
return new RejectedPromise("进一步处理失败:" . $reason->getMessage()); // 拒绝继续传递
})
->then(null, function ($finalReason) {
echo "最终错误处理:" . $finalReason . "\n";
});
// 强制等待所有 Promise 完成,以便在脚本结束前看到结果
// 在实际应用中,你可能需要一个事件循环来异步处理它们
// 注意:这里为了演示效果,我们同步等待。
// 对于真正的异步非阻塞,需要与事件循环集成(如 ReactPHP)
$successPromise->wait();
$failurePromise->wait();
echo "所有命令执行完毕。\n";在这个例子中,我们创建了一个
executeCommandAsync
Promise
Promise
ghostwriter/shell
resolve
reject
通过
then()
otherwise()
guzzlehttp/promises
wait()
wait(true)
wait(false)
结合
ghostwriter/shell
guzzlehttp/promises
ghostwriter/shell
guzzlehttp/promises
otherwise()
then(null, $onRejected)
guzzlehttp/promises
all()
some()
实际应用场景:
git pull
composer install
php artisan migrate
告别 PHP 中外部命令执行的“野蛮生长”时代,拥抱
ghostwriter/shell
guzzlehttp/promises
以上就是PHP命令执行的艺术:如何用Composer结合ghostwriter/shell和guzzlehttp/promises优雅管理复杂任务的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号