Sebelum kalkulator kita bisa menghitung apa pun, program harus tahu lebih dulu cara menerima perintah, cara melaporkan penggunaan yang salah, dan cara memberi tahu sistem operasi bahwa eksekusi berhasil atau gagal. Bagian pertama proyek ini membangun kerangka tersebut: satu berkas main.php yang membaca argumen baris perintah, meneruskan perintah ke handler yang sesuai, dan mengembalikan exit code yang disiplin. Logika aritmatika sengaja belum ditulis — perintah hitung masih berupa stub — supaya kita bisa memfokuskan perhatian pada struktur program tanpa tergoda mengutak-atik detail hitungan. Kerangka yang dipasang di sini akan menopang seluruh bagian berikutnya, jadi mari kita rancang dengan sadar, bukan asal jalan.
Kontrak Perintah dan Exit Code #
Program CLI yang baik punya kontrak yang jelas: daftar perintah yang dikenali, bentuk argumen yang diharapkan, dan exit code untuk setiap kemungkinan hasil. Kontrak adalah janji program kepada pemanggilnya — pemanggil bisa berupa pengguna di terminal, skrip shell, atau pipeline otomatis. Kontrak main.php pada bagian ini dirangkum di tabel berikut:
| Pemanggilan | Perilaku | Exit code |
|---|---|---|
php main.php | Cetak panduan pemakaian | 0 |
php main.php versi | Cetak nama dan versi program | 0 |
php main.php hitung <angka1> <operator> <angka2> | Belum diimplementasikan (stub) | 1 |
php main.php <perintah lain> | Pesan error lalu cetak panduan | 1 |
Ada satu keputusan desain yang perlu ditegaskan: dipanggil tanpa argumen, program mencetak panduan pemakaian dan keluar dengan exit code 0, bukan 1. Alasannya, satu-satunya tugas yang masuk akal ketika pengguna belum memberi perintah adalah menjelaskan cara memakai program — dan program berhasil menjalankan tugas itu. Exit code 1 kita simpan untuk pemanggilan yang salah bentuk, misalnya perintah yang tidak dikenal.
Membaca Argumen dari $argv #
Saat PHP dijalankan dari terminal, seluruh argumen baris perintah tersedia dalam variabel $argv — sebuah array yang elemen pertamanya adalah nama skrip itu sendiri, diikuti argumen pengguna sebagai string. Ukuran array tersebut tercermin dalam $argc. Contoh nyata: pemanggilan php main.php hitung 5 + 3 menghasilkan $argv berisi ['main.php', 'hitung', '5', '+', '3'].
Karena contoh di halaman ini harus bisa berdiri sendiri dan diverifikasi otomatis, blok berikut memakai array simulasi yang isinya sama persis dengan $argv nyata:
<?php
// Simulasi pemanggilan: php main.php hitung 5 + 3
$argvSimulasi = ['main.php', 'hitung', '5', '+', '3'];
// Elemen pertama adalah nama skrip — buang untuk mendapatkan argumen pengguna.
$argumen = array_slice($argvSimulasi, 1);
echo 'jumlah argumen : ' . count($argumen) . "\n";
echo 'perintah : ' . $argumen[0] . "\n";
echo 'argumen perintah : ' . implode(', ', array_slice($argumen, 1)) . "\n";Output yang Dihasilkan:
jumlah argumen : 4
perintah : hitung
argumen perintah : 5, +, 3Mari kita telaah baris-baris pentingnya:
- Baris
array_slice($argvSimulasi, 1): membuang elemen indeks 0 (nama skrip) sehingga yang tersisa murni milik pengguna —['hitung', '5', '+', '3']. - Baris
count($argumen): menghitung empat argumen setelah nama skrip dibuang. - Baris
$argumen[0]: perintah yang diminta selalu berada di posisi pertama argumen pengguna. - Baris
implode(', ', ...): menggabungkan sisa argumen menjadi satu string agar mudah dicetak;array_slicekedua mengambil elemen mulai indeks 1.
Pola “buang nama skrip, ambil perintah, sisanya argumen perintah” persis ini yang dipakai fungsi main() di berkas main.php.
Kerangka main.php: Konstanta, Fungsi, dan Dispatch #
Berkas main.php pada bagian bawah halaman (“Berkas Sumber”) disusun dari potongan-potongan kecil yang masing-masing punya satu tanggung jawab. Konstanta APP_NAME dan APP_VERSION menyimpan identitas program di satu tempat. Fungsi printUsage() mencetak panduan pemakaian, commandVersi() menangani perintah versi, commandHitung() menjadi stub untuk perintah hitung, dan unknownCommand() merapikan jalur perintah asing. Fungsi main() menjadi satu-satunya titik dispatch: membaca $argv, menentukan perintah, lalu mengembalikan exit code dari handler yang dipilih.
Inti dispatch-nya memakai ekspresi match yang sudah kita kenal dari Chapter Match Expression
. Versi ringkasnya terlihat seperti ini:
<?php
function cetakVersi(): int
{
echo 'Kalkulator Terminal versi 0.1.0' . "\n";
return 0;
}
function perintahTidakDikenal(string $perintah): int
{
fwrite(STDERR, "Error: perintah tidak dikenal: {$perintah}\n");
return 1;
}
function jalankanPerintah(string $perintah): int
{
return match ($perintah) {
'versi' => cetakVersi(),
default => perintahTidakDikenal($perintah),
};
}
$exitCode = jalankanPerintah('versi');
echo "exit code: {$exitCode}\n";Output yang Dihasilkan:
Kalkulator Terminal versi 0.1.0
exit code: 0Tiga hal terjadi pada contoh di atas. Pertama, setiap handler mengembalikan int — exit code — alih-alih memanggil exit() di dalam tubuhnya; dengan begitu handler tetap bisa dipanggil dan diuji seperti fungsi biasa. Kedua, match membandingkan $perintah secara strict terhadap arm yang tersedia, dan arm default menampung semua perintah asing. Ketiga, pesan error ditulis lewat fwrite(STDERR, ...) sehingga keluaran error terpisah dari keluaran normal — keputusan yang dihargai oleh skrip yang memanggil program kita.
Baris terakhir berkas main.php hanyalah exit(main($argv)); — hasil fungsi main() diturunkan langsung menjadi exit code proses.
Menjalankan dan Menguji Kerangka #
Mari kita jalankan kerangka ini sungguhan dari direktori bagian ini. Setiap pemanggilan diikuti echo "Exit code: $?" agar kontrak exit code terlihat mata:
cd content/php/proyek-php/kalkulator-terminal/bagian-1-struktur-program
php main.php; echo "Exit code: $?"Pemakaian:
php main.php hitung <angka1> <operator> <angka2>
php main.php versi
Operasi yang didukung:
+ - * / % ** intdiv
Exit code: 0Perintah versi membuktikan dispatch bekerja sampai handler-nya:
php main.php versi; echo "Exit code: $?"Kalkulator Terminal versi 0.1.0
Exit code: 0Sementara perintah hitung untuk sekarang jujur mengakui dirinya belum siap — pesan ini dikirim ke STDERR lalu program keluar dengan exit code 1:
php main.php hitung 5 + 3; echo "Exit code: $?"Error: perintah hitung belum diimplementasikan pada Bagian 1.
Exit code: 1Status Kerangka dan Langkah Berikutnya #
Sampai di sini, yang sudah bekerja: pembacaan $argv, dispatch perintah lewat match, panduan pemakaian, perintah versi, laporan perintah tak dikenal, dan disiplin exit code. Yang belum: perintah hitung masih stub dan sama sekali belum menyentuh angka. Bagian 2 akan mengisi stub itu — mengubah string argumen menjadi angka, memetakan tujuh operator aritmatika, dan mencetak hasil pertama yang sesungguhnya.
Referensi #
- Using PHP from the command line
— perilaku
$argv,$argc, dan konstantaSTDERRpada SAPI CLI. - $argv — dokumentasi resmi array argumen baris perintah.
- match expression
— dasar dispatch yang dipakai fungsi
main(). - Functions
— aturan nilai balik dan deklarasi tipe
intpada handler.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
main.php
Unduh berkas<?php
declare(strict_types=1);
/**
* Kalkulator Terminal — Bagian 1: Struktur Program.
*
* Pemakaian:
* php main.php hitung <angka1> <operator> <angka2>
* php main.php versi
*
* Dipanggil tanpa argumen, program mencetak panduan pemakaian lalu
* keluar dengan exit code 0.
*/
const APP_NAME = 'Kalkulator Terminal';
const APP_VERSION = '0.1.0';
/** Cetak panduan pemakaian program ke STDOUT. */
function printUsage(): void
{
echo "Pemakaian:\n";
echo " php main.php hitung <angka1> <operator> <angka2>\n";
echo " php main.php versi\n";
echo "\n";
echo "Operasi yang didukung:\n";
echo " + - * / % ** intdiv\n";
}
/** Tangani perintah `versi`: cetak nama dan versi program. */
function commandVersi(): int
{
echo APP_NAME . ' versi ' . APP_VERSION . "\n";
return 0;
}
/** Tangani perintah `hitung` — masih stub pada Bagian 1. */
function commandHitung(array $args): int
{
fwrite(STDERR, "Error: perintah hitung belum diimplementasikan pada Bagian 1.\n");
return 1;
}
/** Laporkan perintah yang tidak dikenal, lalu cetak panduan pemakaian. */
function unknownCommand(string $command): int
{
fwrite(STDERR, "Error: perintah tidak dikenal: {$command}\n");
printUsage();
return 1;
}
/**
* Titik masuk program: terima $argv, tentukan perintah yang diminta,
* dan kembalikan exit code ke pemanggil.
*/
function main(array $argv): int
{
// Buang nama skrip (elemen pertama) — sisanya adalah argumen pengguna.
$args = array_slice($argv, 1);
// Tanpa argumen: pengguna hanya butuh tahu cara memakai program.
if ($args === []) {
printUsage();
return 0;
}
$command = $args[0];
$commandArgs = array_slice($args, 1);
return match ($command) {
'versi' => commandVersi(),
'hitung' => commandHitung($commandArgs),
default => unknownCommand($command),
};
}
exit(main($argv));