脚本#
什么是脚本?#
在 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 在
install
或update
之前不会对您的依赖项的状态做出任何假设。因此,您不应在pre-update-cmd
或pre-install-cmd
事件钩子中指定需要 Composer 管理的依赖项的脚本。如果您需要在install
或update
之前执行脚本,请确保它们在您的根包中是自包含的。
定义脚本#
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 install
或 update
命令运行期间,名为 COMPOSER_DEV_MODE
的变量将被添加到环境中。如果命令使用 --no-dev
标志运行,则此变量将设置为 0,否则将设置为 1。该变量在 dump-autoload
运行时也可用,并且将设置为与上次运行的 install
或 update
相同的值。
事件类#
当事件被触发时,您的 PHP 回调会将 Composer\EventDispatcher\Event
对象作为第一个参数接收。此对象具有 getName()
方法,允许您检索事件名称。
根据脚本类型,您将获得各种事件子类,这些子类包含具有相关数据和关联对象的各种 getter
- 基类:
Composer\EventDispatcher\Event
- 命令事件:
Composer\Script\Event
- 安装程序事件:
Composer\Installer\InstallerEvent
- 包事件:
Composer\Installer\PackageEvent
- 插件事件
- init:
Composer\EventDispatcher\Event
- command:
Composer\Plugin\CommandEvent
- pre-file-download:
Composer\Plugin\PreFileDownloadEvent
- post-file-download:
Composer\Plugin\PostFileDownloadEvent
- init:
手动运行脚本#
如果您想手动运行事件的脚本,语法如下
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"]
}
}
别名提供备用命令名称。
注意:只能设置自定义命令的自定义别名。
发现错别字?文档有错误?分叉并编辑它!