Setiap proyek punya daftar perintah yang diulang terus-menerus: jalankan test, periksa gaya kode, bangun autoloader produksi, bersihkan cache. Menghafal dan mengetik perintah panjang tersebut rawan salah, dan anggota tim baru harus membaca dokumentasi hanya untuk tahu cara menjalankan test. Composer menyediakan solusi bawaan bernama scripts: perintah shortcut yang kita definisikan sendiri di composer.json, plus event hook yang otomatis dijalankan pada titik-titik penting seperti setelah instalasi dependensi. Pada chapter ini kita membangun demo nyata — runner test sederhana beserta shortcut-nya — lalu membedah event, prefix @php, dan cara meneruskan argumen.
Shortcut untuk Perintah Rutin #
Kunci scripts di composer.json memetakan nama perintah menjadi baris perintah yang sesungguhnya. Kita siapkan proyek demo-scripts berisi runner test kecil di tests/run.php:
<?php
declare(strict_types=1);
function slug(string $judul): string
{
$kecil = mb_strtolower(trim($judul));
$bersih = preg_replace('/[^a-z0-9]+/', '-', $kecil);
return trim($bersih, '-');
}
$opsi = getopt('', ['filter:']);
$filter = $opsi['filter'] ?? '';
$semuaTes = [
'slug menormalkan judul' => [' Belajar PHP Dasar ', 'belajar-php-dasar'],
'slug menghapus tanda baca' => ['Halo, Dunia!', 'halo-dunia'],
'slug teks kosong' => [' ', ''],
];
$jumlah = 0;
$gagal = 0;
foreach ($semuaTes as $nama => [$masukan, $diharapkan]) {
if ($filter !== '' && !str_contains($nama, $filter)) {
continue;
}
$jumlah++;
$hasil = slug($masukan);
if ($hasil === $diharapkan) {
echo "OK - $nama\n";
} else {
$gagal++;
echo "GAGAL - $nama (diharapkan '$diharapkan', didapat '$hasil')\n";
}
}
echo "\n$jumlah tes dijalankan, $gagal gagal\n";
exit($gagal > 0 ? 1 : 0);Runner ini menguji satu fungsi slug() terhadap tiga kasus, mencetak hasil per tes, lalu mengembalikan exit code 1 bila ada yang gagal — perilaku penting untuk integrasi CI nanti. Sekarang kita daftarkan shortcut-nya:
{
"name": "budi/demo-scripts",
"require": {
"php": ">=8.1"
},
"scripts": {
"test": "php tests/run.php"
}
}Setelah itu, perintah composer test menjadi pintasan resmi proyek:
cd demo-scripts
composer testOutput yang Dihasilkan:
OK - slug menormalkan judul
OK - slug menghapus tanda baca
OK - slug teks kosong
3 tes dijalankan, 0 gagalBentuk eksplisitnya adalah composer run <nama>. Keduanya menjalankan script yang sama, dengan satu perbedaan kecil pada tampilan: composer run test menggemakan perintah aslinya lewat baris > php tests/run.php sebelum outputnya, sedangkan pemanggilan langsung composer test langsung menampilkan hasil:
composer run testOutput yang Dihasilkan:
> php tests/run.php
OK - slug menormalkan judul
OK - slug menghapus tanda baca
OK - slug teks kosong
3 tes dijalankan, 0 gagalNilai dari shortcut ini tumbuh seiring proyek: composer test tetap satu kata walau runner di belakangnya berganti dari skrip kustom ke PHPUnit, dan anggota tim cukup menghafal satu antarmuka yang sama di semua proyek. Daftar script yang tersedia bisa dilihat kapan saja dengan composer run-script --list:
scripts:
test Runs the test script as defined in composer.json
versi Runs the versi script as defined in composer.json
post-autoload-dump
post-install-cmdEvent pre dan post #
Selain shortcut manual, scripts bisa menempel pada event siklus hidup Composer. Nama-nama seperti post-install-cmd bukan perintah yang kita panggil, melainkan pemicu yang Composer jalankan sendiri pada momen tertentu:
| Event | Dijalankan pada |
|---|---|
pre-install-cmd / post-install-cmd | sebelum / sesudah composer install |
pre-update-cmd / post-update-cmd | sebelum / sesudah composer update |
pre-autoload-dump / post-autoload-dump | sebelum / sesudah autoloader dibangun (termasuk saat install, update, dan dump-autoload) |
pre-package-install / post-package-install | setiap satu paket selesai dipasang |
pre-package-update / post-package-update | setiap satu paket selesai diperbarui |
pre-package-uninstall / post-package-uninstall | setiap satu paket selesai dihapus |
post-root-package-install | setelah paket utama terpasang pada composer create-project |
post-create-project-cmd | setelah composer create-project selesai |
Kita tambahkan dua event ke composer.json:
{
"name": "budi/demo-scripts",
"require": {
"php": ">=8.1"
},
"scripts": {
"test": "php tests/run.php",
"post-autoload-dump": [
"echo 'Autoloader diperbarui.'"
],
"post-install-cmd": [
"echo 'Dependensi terpasang.'"
]
}
}Nilai script juga boleh berupa array seperti di atas — Composer menjalankan isinya berurutan. Sekarang setiap composer install otomatis mengeksekusi kedua event:
composer installOutput yang Dihasilkan:
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating autoload files
> echo 'Autoloader diperbarui.'
Autoloader diperbarui.
> echo 'Dependensi terpasang.'
Dependensi terpasang.Urutan pada output tersebut mencerminkan urutan event yang sebenarnya: autoloader dibangun lebih dulu (post-autoload-dump menyala tepat setelah Generating autoload files), kemudian proses install ditutup dengan post-install-cmd. Pola seperti ini dipakai framework sungguhan — Laravel misalnya membersihkan cache dan menyalin berkas konfigurasi lewat post-autoload-dump setiap kali dependensi dipasang.
Menjalankan PHP dengan @php #
Baris perintah di dalam scripts dieksekusi lewat shell, dan itu menimbulkan satu pertanyaan praktis: PHP yang mana yang dipakai bila kita menulis php ...? Jawabannya bergantung pada PATH mesin — bisa berbeda antara laptop, server CI, dan produksi. Prefix @php menghilangkan keraguan itu: Composer menjalankan perintah dengan binary PHP yang sama yang sedang menjalankan Composer sendiri:
{
"scripts": {
"versi": "@php -r 'echo \"PHP \" . PHP_VERSION . PHP_EOL;'"
}
}composer versiOutput yang Dihasilkan:
PHP 8.4.23Prefix ini adalah satu-satunya cara yang andal untuk skrip PHP lintas-mesin, karena proyek tidak perlu berasumsi letak binary PHP di PATH. Composer juga mengenali beberapa prefix kerabatnya seperti @putenv untuk menyetel variabel lingkungan dan @trigger-error untuk menaikkan error internal, semuanya dijalankan di dalam proses Composer tanpa membuka shell baru — lebih cepat dan bebas dari keanehan quoting antar-sistem-operasi.
Meneruskan Argumen dengan – #
Runner test sungguhan hampir selalu punya opsi: filter kasus uji, mode verbose, seed tertentu. Argumen tersebut bisa diteruskan dari shortcut dengan pemisah -- — Composer mengambil semua yang tertulis setelah pemisah dan menyambungkannya ke akhir baris perintah script:
composer test -- --filter=bacaOutput yang Dihasilkan:
OK - slug menghapus tanda baca
1 tes dijalankan, 0 gagalHanya satu tes yang berjalan karena runner kita membaca --filter lewat getopt() lalu menyaring nama tes yang mengandung kata baca. Pemisah -- penting: tanpa pemisah tersebut, Composer akan mencoba membaca opsi sebagai miliknya sendiri dan menolak opsi yang tidak dikenalnya.
Satu perilaku terakhir yang membuat scripts cocok untuk otomasi: exit code script menjadi exit code Composer. Runner kita mengembalikan 1 saat ada tes gagal, sehingga composer test juga berakhir dengan 1 — dan pipeline CI yang menganggap exit code bukan nol sebagai kegagalan akan langsung menandai build merah tanpa konfigurasi tambahan. Kombinasi composer install, composer test, dan pemeriksaan platform — topik chapter berikutnya
— adalah rangkaian standar hampir semua pipeline PHP modern.