Resolusi dependensi yang kita bahas pada chapter sebelumnya menghasilkan folder vendor/ berisi kode semua paket. Composer tidak berhenti di situ: saat instalasi, Composer juga membangun satu berkas penting bernama vendor/autoload.php — pintu masuk tunggal yang membuat semua class dari semua dependensi bisa dipakai tanpa satu pun pernyataan require manual. Pada chapter ini kita bahas autoloading dari sisi manajemen dependensi: bagaimana aturan autoload milik tiap paket digabungkan, strategi files untuk fungsi global, serta cara mengoptimalkan autoloader untuk produksi. Mekanika dasar autoloading dan aturan PSR-4 sudah kita bedah tuntas pada Section Namespaces dan Autoloading .

Satu require untuk Semua Kelas #

Setiap paket yang kita instal membawa konfigurasi autoload di composer.json-nya sendiri — monolog mendaftarkan namespace Monolog\, sedangkan psr/log mendaftarkan Psr\Log. Composer membaca semua konfigurasi itu, milik proyek kita maupun milik seluruh dependensi transitif, lalu menggabungkannya menjadi satu autoloader di vendor/autoload.php. Karena itu kita hanya perlu satu baris di titik masuk aplikasi:

php
<?php

require __DIR__ . '/vendor/autoload.php';

use Monolog\Level;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$log = new Logger('aplikasi');
$log->pushHandler(new StreamHandler(__DIR__ . '/app.log', Level::Warning));
$log->warning('Disk hampir penuh');

Setelah require tersebut, Logger dan StreamHandler tinggal dipakai — PHP memanggil autoloader hanya saat class pertama kali dibutuhkan, dan autoloader tahu persis berkas mana yang harus dimuat karena seluruh peta aturan sudah tergabung. Tidak ada urutan require yang perlu dijaga, dan menambah dependensi baru tidak mengubah cara kita memuat kode lama.

Mendaftarkan Autoload Proyek Sendiri #

Proyek kita punya aturan autoload sendiri yang didaftarkan di kunci autoload pada composer.json. Kita siapkan proyek kecil demo-autoload dengan satu class pembantu dan satu berkas fungsi global:

text
demo-autoload/
├── composer.json
├── helpers/
│   └── functions.php
└── src/
    └── Utilities/
        └── FormatHelper.php

Konfigurasi autoload-nya memakai dua strategi sekaligus:

json
{
    "name": "budi/demo-autoload",
    "require": {
        "php": ">=8.1"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        },
        "files": [
            "helpers/functions.php"
        ]
    }
}

Strategi psr-4 memetakan awalan namespace ke direktori: App\Utilities\FormatHelper dicari di src/Utilities/FormatHelper.php. Isi kedua berkas tersebut sebagai berikut:

php
<?php

declare(strict_types=1);

namespace App\Utilities;

class FormatHelper
{
    public static function rupiah(int $angka): string
    {
        return 'Rp' . number_format($angka, 0, ',', '.');
    }
}
php
<?php

declare(strict_types=1);

use App\Utilities\FormatHelper;

function format_rupiah(int $angka): string
{
    return FormatHelper::rupiah($angka);
}

Setelah menyimpan composer.json, kita minta Composer membuat ulang autoloader dengan composer dump-autoload — perintah ini hanya meregenerasi berkas vendor/composer/* tanpa menjalankan resolusi dependensi, jadi ia cepat dan aman diulang kapan saja:

bash
cd demo-autoload
composer dump-autoload

Output yang Dihasilkan:

text
Generating autoload files
Generated autoload files

Sekarang kita uji dengan skrip kecil coba-autoload.php:

php
<?php

require __DIR__ . '/vendor/autoload.php';

use App\Utilities\FormatHelper;

echo FormatHelper::rupiah(250000), "\n";
echo format_rupiah(75000), "\n";
bash
php coba-autoload.php

Output yang Dihasilkan:

text
Rp250.000
Rp75.000

Baris pertama membuktikan autoloading class bekerja — FormatHelper dimuat otomatis saat pertama dipanggil. Baris kedua membuktikan strategi files bekerja — kita bahas alasannya berikut ini.

files untuk Fungsi Global #

PHP hanya bisa meng-autoload class, interface, trait, dan enum; fungsi dan konstanta global tidak punya mekanisme muat-otomatis. Konsekuensinya, berkas yang mendefinisikan fungsi global harus benar-benar dieksekusi setiap kali aplikasi berjalan — dan itulah tugas strategi files: Composer mencatat berkas-berkas itu lalu memuatnya semua setiap vendor/autoload.php di-require. Pola helpers/functions.php seperti di atas adalah konvensi yang umum dipakai proyek PHP untuk fungsi pembantu (helper) yang ingin dipanggil tanpa namespace.

Penggabungan aturan files milik dependensi bisa kita lihat langsung di dalam vendor/composer/autoload_files.php:

php
<?php

// autoload_files.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'e3ef6eabead08414525284c96aba7f70' => $baseDir . '/helpers/functions.php',
);

Array ini memetakan hash berkas ke lokasinya — satu-satunya entri saat ini milik proyek kita sendiri. Mari kita tambahkan dependensi yang juga memakai strategi files:

bash
composer require symfony/polyfill-mbstring

Output yang Dihasilkan:

text
./composer.json has been updated
Running composer update symfony/polyfill-mbstring
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking symfony/polyfill-mbstring (v1.43.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Downloading symfony/polyfill-mbstring (v1.43.0)
  - Installing symfony/polyfill-mbstring (v1.43.0): Extracting archive
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.
Using version ^1.43 for symfony/polyfill-mbstring

Paket polyfill memang harus memuat berkasnya di setiap request — fungsinya (misalnya mb_strlen()) berupa fungsi global yang tidak bisa ditunda pemuatannya. Setelah instalasi, autoload_files.php kini memuat dua entri:

php
<?php

// autoload_files.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
    'e3ef6eabead08414525284c96aba7f70' => $baseDir . '/helpers/functions.php',
);

Inilah wujud penggabungan (merging) yang dimaksud: aturan files dari proyek kita dan dari setiap dependensi berada dalam satu daftar yang sama, diurutkan menurut urutan dependensinya — berkas dependensi dimuat lebih dulu agar tersedia saat berkas proyek kita dieksekusi. Skrip coba-autoload.php tetap berjalan dengan hasil yang sama, kini dengan polyfill yang ikut termuat di balik layar.

dump-autoload dan Optimasi Produksi #

Secara bawaan, autoloader PSR-4 mencari berkas class dengan menghitung path saat runtime — murah, tetapi tetap ada biaya stat filesystem setiap kali class baru dimuat. Untuk produksi, Composer bisa membangun classmap: daftar lengkap “nama class → berkas” hasil memindai seluruh kode:

bash
composer dump-autoload -o

Output yang Dihasilkan:

text
Generating optimized autoload files
Generated optimized autoload files containing 3 classes

Hasil pemindaian itu disimpan di vendor/composer/autoload_classmap.php:

php
<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'App\\Utilities\\FormatHelper' => $baseDir . '/src/Utilities/FormatHelper.php',
    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
    'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
);

Pemetaan langsung seperti ini menghapus tebakan path saat runtime. Mode paling agresif menambahkan --classmap-authoritative:

bash
composer dump-autoload -o --classmap-authoritative

Output yang Dihasilkan:

text
Generating optimized autoload files (authoritative)
Generated optimized autoload files (authoritative) containing 3 classes

Dengan mode authoritative, autoloader menyatakan classmap adalah satu-satunya kebenaran: class yang tidak ada di daftar langsung dianggap tidak ada, tanpa pencarian filesystem sebagai cadangan. Ini tercepat, tetapi berbahaya bila ada class baru yang belum terdaftar — karena itu perintah ini hanya dijalankan setelah semua dependensi terpasang final, biasanya di langkah deploy atau CI, bukan saat pengembangan sehari-hari.

Setelah semua dependensi terpasang dan autoloader tersedia, langkah berikutnya adalah mengotomatiskan tugas-tugas rutin proyek — menjalankan test, linter, hingga pembersihan cache — tanpa menghafal perintah panjang. Untuk itu Composer menyediakan scripts, topik chapter berikutnya .

Referensi #