Composer 脚本与钩子 #
脚本概述 #
Composer 脚本允许你在 Composer 执行过程中运行自定义命令,用于自动化各种开发任务。
基本配置 #
json
{
"scripts": {
"test": "phpunit",
"build": "php build.php",
"clear-cache": "rm -rf cache/*"
}
}
运行脚本 #
bash
# 运行脚本
composer test
# 或使用 run-script
composer run-script test
# 传递参数
composer test -- --filter=MyTest
# 运行多个脚本
composer run-script test build
脚本类型 #
命令行脚本 #
直接执行命令行命令:
json
{
"scripts": {
"clear-cache": "rm -rf cache/*",
"migrate": "php artisan migrate",
"seed": "php artisan db:seed"
}
}
PHP 回调 #
调用 PHP 类的静态方法:
json
{
"scripts": {
"post-install-cmd": "MyVendor\\MyClass::postInstall",
"post-update-cmd": "MyVendor\\MyClass::postUpdate"
}
}
PHP 类实现:
php
<?php
namespace MyVendor;
class MyClass
{
public static function postInstall(Event $event)
{
$event->getIO()->write("Post install script executed!");
}
public static function postUpdate(Event $event)
{
$event->getIO()->write("Post update script executed!");
}
}
组合脚本 #
组合多个脚本:
json
{
"scripts": {
"test": "phpunit",
"lint": "phpcs --standard=PSR12 src/",
"fix": "phpcbf --standard=PSR12 src/",
"check": [
"@lint",
"@test"
]
}
}
事件钩子 #
事件类型 #
Composer 支持以下事件:
| 事件 | 触发时机 |
|---|---|
pre-install-cmd |
install 命令之前 |
post-install-cmd |
install 命令之后 |
pre-update-cmd |
update 命令之前 |
post-update-cmd |
update 命令之后 |
pre-status-cmd |
status 命令之前 |
post-status-cmd |
status 命令之后 |
pre-package-install |
包安装之前 |
post-package-install |
包安装之后 |
pre-package-update |
包更新之前 |
post-package-update |
包更新之后 |
pre-package-uninstall |
包卸载之前 |
post-package-uninstall |
包卸载之后 |
pre-autoload-dump |
自动加载生成之前 |
post-autoload-dump |
自动加载生成之后 |
post-root-package-install |
根包安装之后 |
post-create-project-cmd |
create-project 之后 |
事件配置 #
json
{
"scripts": {
"pre-install-cmd": "MyVendor\\MyClass::preInstall",
"post-install-cmd": [
"MyVendor\\MyClass::postInstall",
"php artisan optimize"
],
"pre-update-cmd": "MyVendor\\MyClass::preUpdate",
"post-update-cmd": "MyVendor\\MyClass::postUpdate",
"pre-autoload-dump": "MyVendor\\MyClass::preAutoloadDump",
"post-autoload-dump": [
"MyVendor\\MyClass::postAutoloadDump",
"php artisan package:discover"
]
}
}
常用脚本示例 #
测试相关 #
json
{
"scripts": {
"test": "phpunit",
"test-coverage": "phpunit --coverage-html coverage",
"test-parallel": "paratest --processes 4",
"test-watch": "phpunit-watcher watch"
}
}
代码质量 #
json
{
"scripts": {
"lint": "phpcs --standard=PSR12 src/",
"lint-fix": "phpcbf --standard=PSR12 src/",
"stan": "phpstan analyse src/",
"mess": "phpmd src/ text cleancode,codesize,controversial,design,naming,unusedcode",
"check": [
"@lint",
"@stan",
"@test"
]
}
}
清理缓存 #
json
{
"scripts": {
"clear-cache": "rm -rf cache/*",
"clear-all": [
"rm -rf cache/*",
"rm -rf storage/logs/*",
"rm -rf storage/framework/views/*"
]
}
}
数据库操作 #
json
{
"scripts": {
"migrate": "php artisan migrate",
"migrate-fresh": "php artisan migrate:fresh --seed",
"seed": "php artisan db:seed",
"db-reset": [
"php artisan migrate:fresh",
"php artisan db:seed"
]
}
}
构建与部署 #
json
{
"scripts": {
"build": [
"@composer install --no-dev --optimize-autoloader",
"php artisan config:cache",
"php artisan route:cache",
"php artisan view:cache"
],
"deploy": [
"@build",
"php artisan optimize"
]
}
}
开发环境 #
json
{
"scripts": {
"serve": "php artisan serve",
"watch": "npm run watch",
"dev": [
"composer install",
"npm install",
"npm run dev"
]
}
}
事件对象 #
Event 类 #
php
<?php
namespace Composer\Script;
use Composer\Composer;
use Composer\IO\IOInterface;
class Event
{
public function getName(): string {}
public function getComposer(): Composer {}
public function getIO(): IOInterface {}
public function isDevMode(): bool {}
public function getOriginatingEvent(): ?Event {}
public function getArguments(): array {}
public function getFlags(): array {}
}
使用示例 #
php
<?php
namespace App\Scripts;
use Composer\Script\Event;
use Composer\IO\IOInterface;
class InstallHandler
{
public static function postInstall(Event $event)
{
$io = $event->getIO();
$composer = $event->getComposer();
$io->write("<info>Running post-install script...</info>");
if ($event->isDevMode()) {
$io->write("Development mode enabled");
}
$arguments = $event->getArguments();
if (!empty($arguments)) {
$io->write("Arguments: " . implode(', ', $arguments));
}
}
}
PackageEvent 类 #
用于包相关事件:
php
<?php
namespace App\Scripts;
use Composer\Installer\PackageEvent;
class PackageHandler
{
public static function postPackageInstall(PackageEvent $event)
{
$package = $event->getOperation()->getPackage();
$io = $event->getIO();
$io->write("<info>Installed: {$package->getName()}</info>");
$io->write("Version: {$package->getVersion()}");
}
}
脚本引用 #
引用其他脚本 #
使用 @ 前缀引用其他脚本:
json
{
"scripts": {
"lint": "phpcs src/",
"test": "phpunit",
"check": [
"@lint",
"@test"
],
"ci": [
"@check",
"@build"
]
}
}
引用 Composer 命令 #
json
{
"scripts": {
"update-deps": "@composer update --with-dependencies",
"install-prod": "@composer install --no-dev --optimize-autoloader",
"dump-autoload": "@composer dump-autoload --optimize"
}
}
条件脚本 #
根据环境执行 #
php
<?php
namespace App\Scripts;
use Composer\Script\Event;
class EnvironmentHandler
{
public static function postInstall(Event $event)
{
$io = $event->getIO();
if ($event->isDevMode()) {
$io->write("Development environment setup");
self::setupDevEnvironment($io);
} else {
$io->write("Production environment setup");
self::setupProdEnvironment($io);
}
}
private static function setupDevEnvironment($io)
{
$io->write("Setting up development tools...");
}
private static function setupProdEnvironment($io)
{
$io->write("Optimizing for production...");
}
}
交互式脚本 #
php
<?php
namespace App\Scripts;
use Composer\Script\Event;
class InteractiveHandler
{
public static function configure(Event $event)
{
$io = $event->getIO();
$name = $io->ask("What is your name? ", "Guest");
$io->write("Hello, $name!");
$confirm = $io->askConfirmation("Do you want to continue? ", true);
if (!$confirm) {
$io->write("Aborted.");
return;
}
$choice = $io->select(
"Choose an option: ",
['Option 1', 'Option 2', 'Option 3'],
0
);
$io->write("You selected: Option " . ($choice + 1));
}
}
脚本描述 #
添加描述信息 #
json
{
"scripts": {
"test": "phpunit",
"test-description": "Run the test suite",
"lint": "phpcs src/",
"lint-description": "Check code style"
}
}
使用 scripts-descriptions #
json
{
"scripts": {
"test": "phpunit",
"lint": "phpcs src/",
"build": "php build.php"
},
"scripts-descriptions": {
"test": "Run the test suite",
"lint": "Check code style against PSR-12",
"build": "Build the production assets"
}
}
查看描述:
bash
composer run-script --list
跳过脚本 #
命令行跳过 #
bash
# 跳过所有脚本
composer install --no-scripts
# 只跳过特定脚本
composer install --no-plugins
配置跳过 #
json
{
"config": {
"platform": {
"php": "8.1"
}
},
"scripts": {
"post-install-cmd": [
"@php artisan package:discover --ansi"
]
}
}
实际应用场景 #
Laravel 项目 #
json
{
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
]
}
}
Symfony 项目 #
json
{
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
}
}
自定义项目 #
json
{
"scripts": {
"post-install-cmd": [
"App\\Scripts\\InstallHandler::postInstall"
],
"post-update-cmd": [
"App\\Scripts\\InstallHandler::postUpdate"
],
"test": "phpunit",
"lint": "phpcs src/",
"stan": "phpstan analyse src/",
"check": [
"@lint",
"@stan",
"@test"
],
"build": [
"@composer install --no-dev --optimize-autoloader",
"@check"
]
},
"scripts-descriptions": {
"test": "Run unit tests",
"lint": "Check code style",
"stan": "Run static analysis",
"check": "Run all checks (lint, stan, test)",
"build": "Build for production"
}
}
调试脚本 #
详细输出 #
bash
# 增加详细程度
composer install -vvv
# 显示脚本执行
composer run-script test -v
脚本调试 #
php
<?php
namespace App\Scripts;
use Composer\Script\Event;
class DebugHandler
{
public static function debug(Event $event)
{
$io = $event->getIO();
$io->write("<info>Debug Information:</info>");
$io->write("Event: " . $event->getName());
$io->write("Dev Mode: " . ($event->isDevMode() ? 'Yes' : 'No'));
$io->write("Working Dir: " . getcwd());
$arguments = $event->getArguments();
$io->write("Arguments: " . print_r($arguments, true));
}
}
最佳实践 #
1. 使用描述性名称 #
json
{
"scripts": {
"test:unit": "phpunit --testsuite Unit",
"test:feature": "phpunit --testsuite Feature",
"test:coverage": "phpunit --coverage-html coverage"
}
}
2. 组合脚本 #
json
{
"scripts": {
"lint": "phpcs src/",
"test": "phpunit",
"check": [
"@lint",
"@test"
],
"ci": [
"@check",
"@build"
]
}
}
3. 使用 PHP 类处理复杂逻辑 #
php
<?php
namespace App\Scripts;
use Composer\Script\Event;
class ScriptHandler
{
public static function build(Event $event)
{
$io = $event->getIO();
self::clearCache($io);
self::optimizeAutoloader($io);
self::generateAssets($io);
$io->write("<info>Build completed!</info>");
}
private static function clearCache($io)
{
$io->write("Clearing cache...");
}
private static function optimizeAutoloader($io)
{
$io->write("Optimizing autoloader...");
}
private static function generateAssets($io)
{
$io->write("Generating assets...");
}
}
4. 提供有意义的输出 #
php
<?php
$io->write("<info>Success message</info>");
$io->write("<comment>Warning message</comment>");
$io->write("<error>Error message</error>");
下一步 #
现在你已经掌握了脚本与钩子,接下来学习 高级特性 了解私有仓库、平台配置等高级功能!
最后更新:2026-03-28