Sebelum menulis fitur, program CLI yang sehat membutuhkan kerangka: cara menerima instruksi, cara memetakan instruksi ke aksi, dan cara melaporkan hasil ke pemanggil. Pada bagian ini kita membangun kerangka tersebut untuk pengelola daftar tugas — aplikasi yang kelak mampu menambah, menampilkan, menandai selesai, dan menghapus tugas. Daftar tugasnya sendiri masih kosong; fokus kita adalah kontrak program yang jelas supaya bagian-bagian berikutnya tinggal mengisi logika tanpa membongkar struktur.

Kontrak Perintah yang Akan Kita Bangun #

Kita rancang dulu seluruh kontrak perintah proyek ini secara menyeluruh, meskipun baru sebagian yang diimplementasikan hari ini. Mendesain antarmuka lebih dulu membuat keputusan berikutnya lebih mudah karena setiap bagian hanya mengisi slot yang sudah disepakati. Berikut kontrak lengkapnya:

PerintahArgumenFungsi
php main.php—Tampilkan pesan penggunaan
php main.php list—Tampilkan seluruh tugas
php main.php tambah<judul>Tambah tugas baru
php main.php selesai<id>Tandai tugas sebagai selesai
php main.php hapus<id>Hapus tugas

Selain perintah, kita juga menetapkan kontrak exit code. Exit code adalah cara program CLI melaporkan hasil akhirnya kepada sistem operasi, skrip shell, atau pipeline yang menjalankannya.

KodeArti
0Perintah berhasil (termasuk menampilkan bantuan)
1Terjadi kesalahan penggunaan atau data

Membaca Argumen dari Baris Perintah #

PHP menyediakan variabel superglobal $argv (array argumen) dan $argc (jumlah argumen) ketika skrip dijalankan dari CLI. Indeks $argv[0] selalu berisi nama berkas skrip, sehingga perintah pertama yang ditulis pengguna berada di $argv[1]. Mari kita lihat isinya untuk pemanggilan php main.php list:

php
<?php
// Simulasi isi $argv untuk pemanggilan: php main.php list
$argvSimulasi = ['main.php', 'list'];

printf("Nama skrip   : %s\n", $argvSimulasi[0]);
printf("Perintah     : %s\n", $argvSimulasi[1] ?? '(tidak ada)');
printf("Jumlah argumen: %d\n", count($argvSimulasi) - 1);

Output yang Dihasilkan:

text
Nama skrip   : main.php
Perintah     : list
Jumlah argumen: 1

Perhatikan pola ?? '(tidak ada)' — pengguna boleh menjalankan php main.php tanpa perintah sama sekali, sehingga $argv[1] mungkin tidak ada. Null coalescing operator memberi nilai cadangan dan mencegah peringatan Undefined array key.

Dispatch Perintah dengan Ekspresi match #

Inti kerangka kita adalah memetakan isi $argv[1] ke fungsi penangan perintah. PHP 8 menyediakan ekspresi match yang cocok untuk pekerjaan ini: match membandingkan nilai secara ketat (===), tidak jatuh ke cabang berikutnya seperti switch tanpa break, dan mengembalikan nilai sehingga bisa langsung dipakai sebagai ekspresi:

php
<?php
$argvSimulasi = ['main.php', 'list'];

$perintah = $argvSimulasi[1] ?? '';

$aksi = match ($perintah) {
    '' => 'tampilkan bantuan',
    'list' => 'tampilkan daftar tugas',
    'tambah' => 'tambah tugas baru',
    default => "tolak perintah tak dikenal: $perintah",
};

echo $aksi . "\n";

Output yang Dihasilkan:

text
tampilkan daftar tugas

Mari kita telaah blok di atas:

  1. Baris $perintah = $argvSimulasi[1] ?? ''; mengubah argumen yang hilang menjadi string kosong, sehingga cabang '' dapat menangani pemanggilan tanpa perintah.
  2. Ekspresi match ($perintah) membandingkan $perintah dengan setiap kondisi secara berurutan; hasil cabang yang cocok menjadi nilai $aksi.
  3. Cabang default menangkap semua perintah di luar kontrak, misalnya reset atau salah ketik seperti lsit.

Exit Code sebagai Kontrak #

Perintah tak dikenal adalah kegagalan, jadi program harus mencetak pesan error lalu mengembalikan exit code 1. Fungsi exit() menerima integer sebagai status keluar proses; nilai ini bisa dibaca shell melalui variabel $?:

php
<?php
$perintah = 'reset';

$valid = ['', 'list', 'tambah', 'selesai', 'hapus'];

if (!in_array($perintah, $valid, true)) {
    printf("Error: perintah tidak dikenal: %s\n", $perintah);
    exit(1);
}

Output yang Dihasilkan:

text
Error: perintah tidak dikenal: reset

Pemanggilan in_array(..., true) memakai perbandingan ketat agar string seperti '0' tidak dianggap sama dengan ''. Dalam main.php pola yang sama dicapai lewat cabang default dari match.

Struktur main.php #

Berkas main.php pada bagian bawah halaman merangkai semua konsep di atas menjadi program utuh. Strukturnya sederhana: konstanta KELUAR_OK dan KELUAR_GAGAL, satu fungsi penangan per perintah, lalu fungsi jalankan() yang memilih fungsi mana yang dieksekusi:

php
function jalankan(array $argv): int
{
    $perintah = $argv[1] ?? '';

    return match ($perintah) {
        '' => perintahBantuan(),
        'list' => perintahList(),
        default => perintahTidakDikenal($perintah),
    };
}

Setiap cabang match mengembalikan exit code dari fungsi penangannya, dan nilai itulah yang dikembalikan jalankan(). Di akhir berkas ada penjaga eksekusi:

php
if (PHP_SAPI === 'cli' && isset($argv[0]) && realpath($argv[0]) === __FILE__) {
    exit(jalankan($argv));
}

Penjaga ini membandingkan berkas yang dieksekusi ($argv[0]) dengan berkas tempat kode berada (__FILE__). Jika main.php dijalankan langsung, penjaga memanggil exit(jalankan($argv)). Jika main.php justru di-include dari berkas lain — misalnya dari blok contoh di halaman ini — penjaga tidak jalan sehingga kita bisa memanggil jalankan() sendiri dengan argumen buatan. Pola inilah yang membuat program CLI sekaligus bisa diuji tanpa memicu proses baru:

php
<?php
require_once __DIR__ . '/main.php';

$kode = jalankan(['main.php', 'list']);
echo "exit code: $kode\n";

Output yang Dihasilkan:

text
Belum ada tugas.
exit code: 0

Dengan argumen kosong, jalankan() mencetak seluruh pesan penggunaan yang dibangun dari heredoc di dalam perintahBantuan():

php
<?php
require_once __DIR__ . '/main.php';

$kode = jalankan(['main.php']);
echo "exit code: $kode\n";

Output yang Dihasilkan:

text
Pengelola Daftar Tugas — manajemen daftar tugas pribadi

Penggunaan:
  php main.php               Tampilkan bantuan ini
  php main.php list          Tampilkan daftar tugas

Perintah tambah, selesai, dan hapus menyusul pada bagian berikutnya.
exit code: 0

Menjalankan Program #

Dari direktori bagian ini, jalankan perintah berikut dan amati hasilnya:

bash
$ php main.php
text
Pengelola Daftar Tugas — manajemen daftar tugas pribadi

Penggunaan:
  php main.php               Tampilkan bantuan ini
  php main.php list          Tampilkan daftar tugas

Perintah tambah, selesai, dan hapus menyusul pada bagian berikutnya.
bash
$ php main.php list
text
Belum ada tugas.
bash
$ php main.php reset
$ echo $?
text
Error: perintah tidak dikenal atau belum tersedia: reset

Pengelola Daftar Tugas — manajemen daftar tugas pribadi

Penggunaan:
  php main.php               Tampilkan bantuan ini
  php main.php list          Tampilkan daftar tugas

Perintah tambah, selesai, dan hapus menyusul pada bagian berikutnya.
1

Baris terakhir 1 pada contoh terakhir adalah isi $? — exit code dari eksekusi sebelumnya. Tanpa perintah, program keluar dengan 0.

Apa yang Sudah Kita Bangun #

Kerangka kita kini punya tiga fondasi: pembacaan $argv yang aman, dispatch match yang mengembalikan exit code, dan pesan penggunaan yang jujur tentang fitur yang belum ada. Yang belum ada adalah data — list selalu menampilkan daftar kosong dan tambah ditolak sebagai perintah tak dikenal. Bagian 2 mengisi slot tersebut dengan operasi tugas berbasis array.

Ringkasan #

Struktur program menetapkan kontrak lebih dulu: lima perintah, dua exit code, dan satu fungsi penangan per perintah. Ekspresi match menjadi pusat dispatch karena membandingkan secara ketat dan mengembalikan nilai, sementara penjaga realpath($argv[0]) === __FILE__ membuat main.php tetap bisa di-include untuk pengujian. Dengan kerangka stabil, kita siap mengoperasikan data tugas dengan array pada Bagian 2.

Referensi #

  • Using PHP from the command line — dokumentasi resmi $argv, $argc, dan konstanta CLI.
  • match — perilaku perbandingan ketat dan nilai balik ekspresi match.
  • exit — mengakhiri skrip dengan status keluar tertentu.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

main.php

Unduh berkas
php
<?php

declare(strict_types=1);

/**
 * Pengelola Daftar Tugas — Bagian 1: Struktur Program.
 *
 * Kerangka aplikasi CLI: pembacaan argumen, dispatch perintah
 * dengan ekspresi match, pesan penggunaan, dan kontrak exit code.
 * Daftar tugas belum memiliki sumber data — perintah list selalu
 * menampilkan daftar kosong sampai Bagian 2.
 */

const KELUAR_OK = 0;
const KELUAR_GAGAL = 1;

function perintahBantuan(): int
{
    echo <<<TEKS
Pengelola Daftar Tugas — manajemen daftar tugas pribadi

Penggunaan:
  php main.php               Tampilkan bantuan ini
  php main.php list          Tampilkan daftar tugas

Perintah tambah, selesai, dan hapus menyusul pada bagian berikutnya.

TEKS;

    return KELUAR_OK;
}

function perintahList(): int
{
    // Sumber data belum ada; Bagian 2 mulai mengisi daftar tugas.
    echo "Belum ada tugas.\n";

    return KELUAR_OK;
}

function perintahTidakDikenal(string $perintah): int
{
    printf("Error: perintah tidak dikenal atau belum tersedia: %s\n\n", $perintah);
    perintahBantuan();

    return KELUAR_GAGAL;
}

/**
 * Titik masuk program: terjemahkan $argv menjadi exit code.
 *
 * $argv[0] berisi nama skrip, perintah berada di $argv[1],
 * dan argumen perintah (judul, ID) berada di $argv[2] dst.
 */
function jalankan(array $argv): int
{
    $perintah = $argv[1] ?? '';

    return match ($perintah) {
        '' => perintahBantuan(),
        'list' => perintahList(),
        default => perintahTidakDikenal($perintah),
    };
}

// Jalankan hanya bila berkas ini dieksekusi langsung sebagai skrip
// CLI, bukan saat di-include dari berkas lain (misalnya blok contoh
// pada halaman materi atau pengujian otomatis).
if (PHP_SAPI === 'cli' && isset($argv[0]) && realpath($argv[0]) === __FILE__) {
    exit(jalankan($argv));
}