有時你需要使用 PHP 應用程式中的作業系統層級命令。讓我們看看我們如何做到這一點,看看我們是否可以讓開發者體驗更好。
在過去的幾年裡,我一直專注於我如何編寫程式碼以及如何改進它的各個方面。我首先研究如何讓與 HTTP 的整合更好、更面向對象。我相信我找到了實現這一目標的方法,現在我將注意力集中在其他地方。 【相關建議:laravel影片教學】
在某些情況下,你希望在應用程式中使用 OS CLI。在 Web 應用程式或另一個 CLI 應用程式中。過去,我們使用過類似 exec
或 passthru
或 shell_exec
和 system
的方法。然後出現了 Symfony Process 元件,我們得救了。
Symfony 進程元件使得與作業系統進程整合並獲得輸出變得非常容易。但是我們如何與這個庫整合仍然有點令人沮喪。我們建立一個新進程,傳入一個參數數組,使我們希望運行的命令。讓我們來看看:
$command = new Process( command: ['git', 'push', 'origin', 'main'], ); $command->run();
這種方法有什麼問題?好吧,老實說,什麼都沒有。但是有沒有辦法改善開發人員的體驗呢?假設我們從 git 切換到 svn(我不太可能知道)。
為了改善開發人員的體驗,首先,我們需要了解邏輯上用於建立 OS 命令的元件。我們可以將它們分解為:
我們的可執行檔是我們直接與之互動的東西,例如php、git、brew 或我們系統上任何其他已安裝的二進位。然後爭論是我們如何互動;這些可以是子命令、選項、標誌或參數。
因此,如果我們稍微抽像一下,我們就會有一個process
和一個command
, 它接受參數。我們將使用介面/契約來定義我們的元件來控制我們的工作流程應該如何運作。讓我們從流程契約開始:
declare(strict_types=1); namespace JustSteveKing\OS\Contracts; use Symfony\Component\Process\Process; interface ProcessContract { public function build(): Process; }
我們這裡是說每個進程都必須能夠被構建,而創建的進程的結果應該是一個 Symfony 進程。我們的流程應該建立一個命令供我們運行,所以現在讓我們看看我們的命令契約:
declare(strict_types=1); namespace JustSteveKing\OS\Contracts; interface CommandContract { public function toArgs(): array; }
我們希望從命令中得到的主要內容是能夠作為參數返回,我們可以將這些參數作為命令傳遞給Symfony 進程。
想法已經夠多了,讓我們來看一個真實的例子。我們將使用 git 作為範例,因為我們大多數人應該能夠與 git 命令相關聯。
首先,讓我們建立一個Git 進程來實現我們剛剛描述的Process Contract:
class Git implements ProcessContract { use HandlesGitCommands; private CommandContract $command; }
我們的流程實作了合約,並且有一個命令屬性,我們將使用它允許我們的流程被流暢地建構和執行。我們有一個特點,可以讓我們集中精力為我們的 Git 流程建立和製造事物的方式。讓我們來看看:
trait HandlesGitCommands { public function build(): Process { return new Process( command: $this->command->toArgs(), ); } protected function buildCommand(Git $type, array $args = []): void { $this->command = new GitCommand( type: $type, args: $args, ); } }
因此,我們的 trait 展示了流程契約本身的實現,並提供了有關如何建立流程的說明。它還包含一個允許我們抽象化建構命令的方法。
到目前為止,我們可以建立一個流程並建立一個潛在的命令。但是,我們還沒有下達命令。我們在 trait 中建立一個新的 Git 命令,它使用 Git 類別作為類型。讓我們看看另一個 Git 類,它是一個枚舉。不過,我將展示一個精簡版本- 實際上,你希望它映射到你希望支持的所有git 子命令:
enum Git: string { case PUSH = 'push'; case COMMIT = 'commit'; }
然後我們將它傳遞給Git 命令:
final class GitCommand implements CommandContract { public function __construct( public readonly Git $type, public readonly array $args = [], public readonly null|string $executable = null, ) { } public function toArgs(): array { $executable = (new ExecutableFinder())->find( name: $this->executable ?? 'git', ); if (null === $executable) { throw new InvalidArgumentException( message: "Cannot find executable for [$this->executable].", ); } return array_merge( [$executable], [$this->type->value], $this->args, ); } }
在在這個類別中,我們接受來自Process 的參數,目前由我們的HandledGitCommands trait 處理。然後我們可以把它變成 Symfony 進程可以理解的參數。我們使用 Symfony 套件中的 ExecutableFinder
來最大程度地減少路徑中的錯誤。但是,如果找不到可執行文件,我們也想拋出異常。
當我們把它們放在我們的Git 進程中時,它看起來有點像這樣:
use JustSteveKing\OS\Commands\Types\Git as SubCommand; class Git implements ProcessContract { use HandlesGitCommands; private CommandContract $command; public function push(string $branch): Process { $this->buildCommand( type: SubCommand:PUSH, args: [ 'origin', $branch, ], ); return $this->build(); } }
現在剩下要做的就是運行程式碼本身,以便我們可以在PHP 應用程式中很好地使用git:
$git = new Git(); $command = $git->push( branch: 'main', ); $result = $command->run();
Push方法的結果將允許你與symfony進程交互-這意味著你可以在另一端使用命令執行所有排序。我們唯一改變的是圍繞這個過程的創建構建了一個面向對象的包裝器。這使我們能夠很好地開發和維護上下文,並以可測試和可擴展的方式擴展事物。
你多久在應用程式中使用作業系統指令?你能想到任何用例嗎?我已經 在 GitHub 上的儲存庫中發布了範例程式碼,以便你可以使用它並查看是否可以改進你的作業系統整合。
一個很好的範例應該是SSH、MySQL,甚至是Anable或Terraform!想像一下,如果你可以按計劃高效地運行來自Laravel Artisan的MySQL轉儲,而無需始終使用第三方程式包!
原文網址:https://laravel-news.com/working-with-os-process-in-php
翻譯網址:https://learnku.com/ laravel/t/71422
更多程式相關知識,請造訪:程式設計影片! !
以上是淺析PHP應用程式中正確呼叫系統指令的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!