指令碼#

什麼是指令碼?#

以 Composer 的說法,指令碼可以是 PHP 回呼 (定義為靜態方法) 或任何命令列可執行指令。在 Composer 執行過程中,指令碼可用於執行套件的自訂程式碼或套件特定指令。

自 Composer 2.5 起,指令碼也可以是 Symfony Console 指令類別,讓您可以輕鬆執行它們,包含傳遞選項。不過,這不建議用於處理事件。

注意:只有在根套件的 composer.json 中定義的指令碼會被執行。如果根套件的相依性指定自己的指令碼,Composer 就不會執行這些額外的指令碼。

事件名稱#

Composer 會在其執行過程中引發以下命名的事件

指令事件#

  • pre-install-cmd:在執行 install 指令且存在鎖定檔案之前發生。
  • post-install-cmd:在執行 install 指令且存在鎖定檔案之後發生。
  • pre-update-cmd:在執行 update 指令之前,或在沒有鎖定檔案的情況下執行 install 指令之前發生。
  • post-update-cmd:在執行 update 指令之後,或在沒有鎖定檔案的情況下執行 install 指令之後發生。
  • pre-status-cmd:在執行 status 指令之前發生。
  • post-status-cmd:在執行 status 指令之後發生。
  • pre-archive-cmd:在執行 archive 指令之前發生。
  • post-archive-cmd:在執行 archive 指令之後發生。
  • pre-autoload-dump:在自動載入器被傾印之前發生,發生的時機是在 install/update 期間,或透過 dump-autoload 指令。
  • post-autoload-dump:自動載入程式傾印後,在 install/update 期間,或透過 dump-autoload 指令執行時所觸發。
  • post-root-package-install:在 root 套件於 create-project 指令執行期間安裝後,所觸發(但其依賴項目尚未安裝之前)。
  • post-create-project-cmd:在 create-project 指令執行後,所觸發。

安裝器事件#

  • pre-operations-exec:在鎖檔安裝時安裝/升級/…運算執行前所觸發。需要串接此事件的插件必須以全域方式安裝,才能使用,否則在專案重新安裝時尚未載入。

套件事件#

  • pre-package-install:在套件安裝前所觸發。
  • post-package-install:在套件安裝後所觸發。
  • pre-package-update:在套件更新前所觸發。
  • post-package-update:在套件更新後所觸發。
  • pre-package-uninstall:在套件解除安裝前所觸發。
  • post-package-uninstall:在套件解除安裝後所觸發。

插件事件#

  • init:在 Composer 執行個體初始化完畢後所觸發。
  • command:在任何 Composer 指令於 CLI 上執行前所觸發。它提供你存取程式輸入和輸出物件。
  • pre-file-download:在檔案下載前所觸發,允許你根據要下載的 URL,在下載檔案之前,調整 HttpDownloader 物件。
  • post-file-download:在套件 dist 檔案下載後所觸發,並允許你在需要時,對檔案執行其他檢查。
  • pre-command-run:在指令執行前所觸發,並允許你調整 InputInterface 物件的選項和引數,以調整指令行為。
  • pre-pool-create:在套件 Pool 建立前所觸發,並讓你過濾將進入求解器的套件清單。

注意:Composer 沒有在 installupdate 前,假設你的依賴項狀態。因此,你不應該在 pre-update-cmdpre-install-cmd 事件鉤中,指定需要 Composer 管理的依賴項的指令碼。如果你需要在 installupdate 之前執行指令碼,請確保它們自我封閉在你的 root 套件內。

定義指令碼#

composer.json 中的根 JSON 物件應該有一個稱作 "scripts" 的屬性,其中包含命名事件對應的指令碼。事件的指令碼可以定義為字串(僅限於單一指令碼)或陣列(單一或多個指令碼)。

對於任何事件

  • 在對應事件觸發時,指令碼依定義順序執行。
  • 連結到單一事件的指令碼陣列,可以包含 PHP 回呼函式和命令列可執行指令碼。
  • 包含已定義回呼的 PHP 類別和命令必須可以使用 Composer 的自動載入功能自動載入。
  • 回呼只能從 psr-0、psr-4 和類別對應定義中自動載入類別。如果已定義的回呼仰賴在類別外部定義的函式,回呼會自行載入含有這些函式的檔案。

指令碼定義範例

{
    "scripts": {
        "post-update-cmd": "MyVendor\\MyClass::postUpdate",
        "post-package-install": [
            "MyVendor\\MyClass::postPackageInstall"
        ],
        "post-install-cmd": [
            "MyVendor\\MyClass::warmCache",
            "phpunit -c app/"
        ],
        "post-autoload-dump": [
            "MyVendor\\MyClass::postAutoloadDump"
        ],
        "post-create-project-cmd": [
            "php -r \"copy('config/local-example.php', 'config/local.php');\""
        ]
    }
}

使用先前的定義範例,以下是用來執行 PHP 回呼的類別 MyVendor\MyClass

<?php

namespace MyVendor;

use Composer\Script\Event;
use Composer\Installer\PackageEvent;

class MyClass
{
    public static function postUpdate(Event $event)
    {
        $composer = $event->getComposer();
        // do stuff
    }

    public static function postAutoloadDump(Event $event)
    {
        $vendorDir = $event->getComposer()->getConfig()->get('vendor-dir');
        require $vendorDir . '/autoload.php';

        some_function_from_an_autoloaded_file();
    }

    public static function postPackageInstall(PackageEvent $event)
    {
        $installedPackage = $event->getOperation()->getPackage();
        // do stuff
    }

    public static function warmCache(Event $event)
    {
        // make cache toasty
    }
}

注意:在執行 Composer installupdate 命令期間,會將名為 COMPOSER_DEV_MODE 的變數新增到環境中。如果該命令以 --no-dev 旗標執行,這個變數會設為 0,否則會設為 1。這個變數在 dump-autoload 執行時也會提供,且會設為最後一次執行 installupdate 時的設定值。

事件類別#

事件觸發後,PHP 回呼會收到 Composer\EventDispatcher\Event 物件。這個物件有一個 getName() 方法,可讓您擷取事件名稱。

根據指令碼類型,您會收到不同的事件子類別,這些子類別包含具有相關資料和關聯物件的各種取得器

手動執行指令碼#

如果您想要手動執行某個事件的指令碼,其語法如下

php composer.phar run-script [--dev] [--no-dev] script

例如,composer run-script post-install-cmd 會執行任何已定義的 post-install-cmd 指令碼和 外掛程式

您也可以透過附加上 -- 字元後面接處理器引數的方式,向指令碼處理器提供額外的引數。例如,composer run-script post-install-cmd -- --check 會將 --check 傳遞給指令碼處理器。這些引數由 CLI 處理器接收為 CLI 參數,PHP 處理器可以用陣列形態透過 $event->getArguments() 來擷取。

撰寫自訂命令#

如果您新增不符合上述預先定義事件名稱的客製化指令碼,您可以透過 run-script 執行它們,也可以將它們當成原生 Composer 指令來執行。例如,以下定義的處理常式可以透過執行 composer test 執行

{
    "scripts": {
        "test": "phpunit",
        "do-something": "MyVendor\\MyClass::doSomething"
        "my-cmd": "MyVendor\\MyCommand"
    }
}

類似於 run-script 指令,您可以為指令碼提供額外引數,例如,composer test -- --filter <pattern> 會將 --filter <pattern> 傳遞給 phpunit 指令碼。

透過 composer do-something arg 使用 PHP 方法,讓您能夠執行 static function doSomething(\Composer\Script\Event $event),而 arg 會在 $event->getArguments() 中可用。不過,這並不允許您輕鬆地以 --flags 形式傳遞自訂選項。

透過使用 symfony/console Command 類別,您可以更輕鬆地定義並存取引數和選項。

例如,使用以下指令,您只需呼叫 composer my-cmd --arbitrary-flag 即可,甚至不需要 -- 分隔符號。為了被偵測為 symfony/console 指令,類別名稱必須以 Command 結尾並延伸 symfony 的 Command 類別。另外,請注意,這會使用 Composer 內建的 symfony/console 版本執行,而該版本可能與您在專案中需要的版本不符,並可能在 Composer 次要版本之間變更。如果您需要更高的安全性保證,您應該使用自己的二進位檔案,才能在獨立的程序中隔離執行自己的 symfony/console 版本。

<?php

namespace MyVendor;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class MyCommand extends Command
{
    protected function configure(): void
    {
        $this->setDefinition([
            new InputOption('arbitrary-flag', null, InputOption::VALUE_NONE, 'Example flag'),
            new InputArgument('foo', InputArgument::OPTIONAL, 'Optional arg'),
        ]);
    }

    public function execute(InputInterface $input, OutputInterface $output): int
    {
        if ($input->getOption('arbitrary-flag')) {
            $output->writeln('The flag was used');
        }

        return 0;
    }
}

注意:在執行指令碼之前,Composer 的 bin-dir 會暫時推進到 PATH 環境變數的頂端,才能直接存取相依項目的二進位檔案。在此範例中,不論 phpunit 二進位檔案實際上位於 vendor/bin/phpunitbin/phpunit 中,都將會被尋找並執行。

管理程序逾時#

雖然 Composer 並非用來管理 PHP 專案的長期執行程序及其他此類面向,但有時在自訂指令中停用程序逾時會很有幫助。此逾時的預設值為 300 秒,可以透過各種方式覆寫,具體取決於所需的效果

  • 使用設定金鑰 process-timeout 為所有指令停用
  • 使用環境變數 COMPOSER_PROCESS_TIMEOUT 為目前或未來呼叫 Composer 停用
  • 針對特定呼叫,使用 run-script 指令的 --timeout 標記
  • 針對特定指令碼,使用靜態輔助程式。

若要直接在 composer.json 中使用靜態輔助程式停用特定指令碼的逾時

{
    "scripts": {
        "test": [
            "Composer\\Config::disableProcessTimeout",
            "phpunit"
        ]
    }
}

若要停用特定專案上每個指令碼的逾時,您可以使用 composer.json 設定檔

{
    "config": {
        "process-timeout": 0
    }
}

也可以設定全域環境變數,以停用目前終端機環境中所有後續指令碼的逾時

export COMPOSER_PROCESS_TIMEOUT=0

若要停用單一指令碼呼叫的逾時,您必須使用 run-script composer 指令並指定 --timeout 參數

php composer.phar run-script --timeout=0 test

腳本參考#

為啟用腳本重複使用並避免重複,您可透過在指令名稱前加 @,在其他指令中呼叫腳本

{
    "scripts": {
        "test": [
            "@clearCache",
            "phpunit"
        ],
        "clearCache": "rm -rf cache/*"
    }
}

您也可以參考腳本並傳遞新參數

{
    "scripts": {
        "tests": "phpunit",
        "testsVerbose": "@tests -vvv"
    }
}

呼叫 Composer 指令#

為呼叫 Composer 指令,您可以使用 @composer,將自動解析為目前正在使用的 composer.phar

{
    "scripts": {
        "test": [
            "@composer install",
            "phpunit"
        ]
    }
}

這項技術的限制是您無法持續呼叫多個 composer 指令,例如 @composer install && @composer foo。您必須使用 JSON 指令陣列將它們區分開來。

執行 PHP 腳本#

若要執行 PHP 腳本,您可以使用 @php,將自動解析為目前正在使用的 php 程序

{
    "scripts": {
        "test": [
            "@php script.php",
            "phpunit"
        ]
    }
}

這項技術的限制是您無法持續呼叫多個指令,例如 @php install && @php foo。您必須使用 JSON 指令陣列將它們區分開來。

您也可以呼叫 shell/bash 腳本,其使用路徑在 PHP 執行檔中可用,作為 PHP_BINARY 環境變數.

設定環境變數#

若要跨平台設定環境變數,您可以使用 @putenv

{
    "scripts": {
        "install-phpstan": [
            "@putenv COMPOSER=phpstan-composer.json",
            "@composer install --prefer-dist"
        ]
    }
}

自訂說明#

您可以在 composer.json 中使用下列方式設定腳本自訂說明

{
    "scripts-descriptions": {
        "test": "Run all tests!"
    }
}

說明用於 composer listcomposer run -l 指令中,說明執行指令時腳本會做什麼。

注意事項:您只能設定自訂指令的自訂說明。

自訂別名#

在 Composer 2.7 中,您可以在 composer.json 中使用下列方式來設定自訂腳本別名

{
    "scripts-aliases": {
        "phpstan": ["stan", "analyze"]
    }
}

別名提供替代性指令名稱。

注意事項:您只能設定自訂指令的自訂別名。

找到錯字嗎?此文件有任何錯誤嗎?Fork 並編輯!