A script, in Composer's terms, can either be a PHP callback (defined as a static method) or any command-line executable command. Scripts are useful for executing a package's custom code or package-specific commands during the Composer execution process.
Note: Only scripts defined in the root package's
composer.jsonare executed. If a dependency of the root package specifies its own scripts, Composer does not execute those additional scripts.
Composer fires the following named events during its execution process:
install command is executed with a
lock file present.install command has been executed
with a lock file present.update command is executed, or before
the install command is executed without a lock file present.update command has been executed, or
after the install command has been executed without a lock file present.status command has been executed.archive command is executed.archive command has been executed.install/update, or via the dump-autoload command.install/update, or via the dump-autoload command.create-project command.create-project command has
been executed.RemoteFilesystem object prior to downloading files
based on the URL to be downloaded.InputInterface object's options and arguments to tweak
a command's behavior.Note: Composer makes no assumptions about the state of your dependencies prior to
installorupdate. Therefore, you should not specify scripts that require Composer-managed dependencies in thepre-update-cmdorpre-install-cmdevent hooks. If you need to execute scripts prior toinstallorupdateplease make sure they are self-contained within your root package.
The root JSON object in composer.json should have a property called
"scripts", which contains pairs of named events and each event's
corresponding scripts. An event's scripts can be defined as either a string
(only for a single script) or an array (for single or multiple scripts.)
For any given event:
Script definition example:
{
"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');\""
]
}
}
Using the previous definition example, here's the class MyVendor\MyClass
that might be used to execute the PHP callbacks:
<?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
}
}
Note: During a composer install or update process, a variable named
COMPOSER_DEV_MODE will be added to the environment. If the command was run
with the --no-dev flag, this variable will be set to 0, otherwise it will be
set to 1.
When an event is fired, your PHP callback receives as first argument a
Composer\EventDispatcher\Event object. This object has a getName() method
that lets you retrieve the event name.
Depending on the script types you will get various event subclasses containing various getters with relevant data and associated objects:
Composer\EventDispatcher\EventComposer\Script\EventComposer\Installer\InstallerEventComposer\Installer\PackageEventComposer\EventDispatcher\EventComposer\Plugin\CommandEventComposer\Plugin\PreFileDownloadEventIf you would like to run the scripts for an event manually, the syntax is:
composer run-script [--dev] [--no-dev] script
For example composer run-script post-install-cmd will run any
post-install-cmd scripts and plugins that have been defined.
You can also give additional arguments to the script handler by appending --
followed by the handler arguments. e.g.
composer run-script post-install-cmd -- --check will pass--check along to
the script handler. Those arguments are received as CLI arg by CLI handlers,
and can be retrieved as an array via $event->getArguments() by PHP handlers.
If you add custom scripts that do not fit one of the predefined event name
above, you can either run them with run-script or also run them as native
Composer commands. For example the handler defined below is executable by
simply running composer test:
{
"scripts": {
"test": "phpunit"
}
}
Similar to the run-script command you can give additional arguments to scripts,
e.g. composer test -- --filter <pattern> will pass --filter <pattern> along
to the phpunit script.
Note: Before executing scripts, Composer's bin-dir is temporarily pushed on top of the PATH environment variable so that binaries of dependencies are easily accessible. In this example no matter if the
phpunitbinary is actually invendor/bin/phpunitorbin/phpunitit will be found and executed.
Although Composer is not intended to manage long-running processes and other such aspects of PHP projects, it can sometimes be handy to disable the process timeout on custom commands. This timeout defaults to 300 seconds and can be overridden in a variety of ways depending on the desired effect:
process-timeout,COMPOSER_PROCESS_TIMEOUT,--timeout flag of the run-script command,To disable the timeout for specific scripts with the static helper directly in composer.json:
{
"scripts": {
"test": [
"Composer\\Config::disableProcessTimeout",
"phpunit"
]
}
}
To disable the timeout for every script on a given project, you can use the composer.json configuration:
{
"config": {
"process-timeout": 0
}
}
It's also possible to set the global environment variable to disable the timeout of all following scripts in the current terminal environment:
export COMPOSER_PROCESS_TIMEOUT=0
To disable the timeout of a single script call, you must use the run-script composer
command and specify the --timeout parameter:
composer run-script --timeout=0 test
To enable script re-use and avoid duplicates, you can call a script from another
one by prefixing the command name with @:
{
"scripts": {
"test": [
"@clearCache",
"phpunit"
],
"clearCache": "rm -rf cache/*"
}
}
You can also refer a script and pass it new arguments:
{
"scripts": {
"tests": "phpunit",
"testsVerbose": "@tests -vvv"
}
}
To call Composer commands, you can use @composer which will automatically
resolve to whatever composer.phar is currently being used:
{
"scripts": {
"test": [
"@composer install",
"phpunit"
]
}
}
One limitation of this is that you can not call multiple composer commands in
a row like @composer install && @composer foo. You must split them up in a
JSON array of commands.
To execute PHP scripts, you can use @php which will automatically
resolve to whatever php process is currently being used:
{
"scripts": {
"test": [
"@php script.php",
"phpunit"
]
}
}
One limitation of this is that you can not call multiple commands in
a row like @php install && @php foo. You must split them up in a
JSON array of commands.
You can also call a shell/bash script, which will have the path to
the PHP executable available in it as a PHP_BINARY env var.
To set an environment variable in a cross-platform way, you can use @putenv:
{
"scripts": {
"install-phpstan": [
"@putenv COMPOSER=phpstan-composer.json",
"composer install --prefer-dist"
]
}
}
You can set custom script descriptions with the following in your composer.json:
{
"scripts-descriptions": {
"test": "Run all tests!"
}
}
Note: You can only set custom descriptions of custom commands.