脚本#

什么是脚本?#

在 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:在 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:在 CLI 上执行任何 Composer 命令之前发生。它允许您访问程序的输入和输出对象。
  • pre-file-download:在下载文件之前发生,并允许您根据要下载的 URL 在下载文件之前操作 HttpDownloader 对象。
  • post-file-download:在下载包 dist 文件后发生,并允许您在需要时对文件执行其他检查。
  • pre-command-run:在执行命令之前发生,并允许您操作 InputInterface 对象的选项和参数以调整命令的行为。
  • pre-pool-create:在创建包池之前发生,并允许您过滤将进入求解器的包列表。

注意:Composer 在 installupdate 之前不会对您的依赖项的状态做出任何假设。因此,您不应在 pre-update-cmdpre-install-cmd 事件钩子中指定需要 Composer 管理的依赖项的脚本。如果您需要在 installupdate 之前执行脚本,请确保它们在您的根包中是自包含的。

定义脚本#

composer.json 中的根 JSON 对象应具有一个名为 "scripts" 的属性,其中包含命名事件对及其每个事件的对应脚本。事件的脚本可以定义为字符串(仅用于单个脚本)或数组(用于单个或多个脚本)。

对于任何给定事件

  • 脚本按定义的顺序执行,当它们的对应事件被触发时。
  • 连接到单个事件的脚本数组可以包含 PHP 回调和命令行可执行命令。
  • 包含已定义回调的 PHP 类和命令必须通过 Composer 的自动加载功能自动加载。
  • 回调只能自动加载来自 psr-0、psr-4 和 classmap 定义的类。如果定义的回调依赖于在类之外定义的函数,则回调本身负责加载包含这些函数的文件。

脚本定义示例

{
    "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() 方法,允许您检索事件名称。

根据脚本类型,您将获得各种事件子类,这些子类包含具有相关数据和关联对象的各种 getter

手动运行脚本#

如果您想手动运行事件的脚本,语法如下

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/phpunit 还是 bin/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 install && @composer foo` 那样连续调用多个 Composer 命令。必须将它们拆分到一个 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 list` 或 `composer run -l` 命令中用于描述运行命令时脚本的作用。

注意:只能设置自定义命令的自定义描述。

自定义别名#

从 Composer 2.7 开始,可以在 `composer.json` 中使用以下内容设置自定义脚本别名。

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

别名提供备用命令名称。

注意:只能设置自定义命令的自定义别名。

发现错别字?文档有错误?分叉并编辑它!