Kerangka dari Bagian 1 sudah siap menerima perintah; sekarang kita mengisinya dengan data. Pada bagian ini setiap tugas kita modelkan sebagai array asosiatif berisi id, judul, dan selesai, lalu kita bangun empat operasi di atasnya: menampilkan, menambah, menandai selesai, dan menghapus. Ada satu batasan penting yang sengaja kita biarkan: daftar tugas hanya hidup di memori, sehingga setiap eksekusi program dimulai dari daftar kosong. Batasan itu akan menjadi motivasi penyimpanan permanen pada Bagian 3.
Tugas sebagai Array Asosiatif #
Satu tugas kita wakili dengan tiga kunci: id (integer, pengenal unik), judul (string), dan selesai (boolean). Seluruh daftar tugas berupa array berindeks numerik yang berisi array-asosiatif tersebut. Mari kita cetak isi dua tugas dengan format yang nanti dipakai di seluruh proyek:
<?php
$tugas = [
['id' => 1, 'judul' => 'Belajar PHP dasar', 'selesai' => false],
['id' => 2, 'judul' => 'Belajar OOP', 'selesai' => true],
];
foreach ($tugas as $t) {
printf("%d. [%s] %s\n", $t['id'], $t['selesai'] ? 'x' : ' ', $t['judul']);
}Output yang Dihasilkan:
1. [ ] Belajar PHP dasar
2. [x] Belajar OOPEkspresi $t['selesai'] ? 'x' : ' ' memilih karakter centang untuk tugas yang selesai dan spasi untuk yang belum — format kotak centang sederhana yang tetap terbaca di terminal mana pun.
Array PHP Disalin, Bukan Dirujuk #
Sebelum menulis operasi, kita perlu pahami satu perilaku khas PHP: array adalah value. Ketika array dimasukkan ke variabel lain atau dikirim ke fungsi, PHP membuat salinan, bukan berbagi isi seperti yang terjadi pada object. Mari kita buktikan:
<?php
$tugas = [
['id' => 1, 'judul' => 'Belajar PHP dasar', 'selesai' => false],
];
$salinan = $tugas;
$salinan[0]['selesai'] = true;
printf("asli : selesai = %s\n", $tugas[0]['selesai'] ? 'true' : 'false');
printf("salinan: selesai = %s\n", $salinan[0]['selesai'] ? 'true' : 'false');Output yang Dihasilkan:
asli : selesai = false
salinan: selesai = trueMengubah $salinan tidak mengubah $tugas karena keduanya adalah data terpisah. Konsekuensinya, setiap operasi pada berkas main.php di bawah halaman ini mengembalikan daftar baru alih-alih mengubah daftar lama secara diam-diam — pola yang membuat alur data mudah diikuti.
Menambah Tugas dengan ID Otomatis #
ID tidak diminta dari pengguna; program yang menghitungnya lewat idBerikutnya() — ambil ID terbesar yang ada, tambah satu. Dengan begitu ID tidak pernah ganda walaupun tugas sudah dihapus. Kedua fungsi berikut berasal langsung dari main.php:
function idBerikutnya(array $tugas): int
{
$terbesar = 0;
foreach ($tugas as $t) {
$terbesar = max($terbesar, $t['id']);
}
return $terbesar + 1;
}
function tambahTugas(array $tugas, string $judul): array
{
$tugas[] = tugasBaru(idBerikutnya($tugas), $judul);
return $tugas;
}Mari kita jalankan operasi penambahan dua kali berturut-turut dan perhatikan penomorannya:
<?php
require_once __DIR__ . '/main.php';
$tugas = tambahTugas([], 'Belajar PHP dasar');
$tugas = tambahTugas($tugas, 'Belajar OOP');
printf("ID tugas berikutnya: %d\n", idBerikutnya($tugas));Output yang Dihasilkan:
ID tugas berikutnya: 3Menandai Selesai dan Menghapus #
Kedua operasi ini mencari tugas berdasarkan ID lewat perulangan, lalu mengubah atau mengeluarkan elemennya. Fungsi tandaiSelesai() mengubah kolom selesai menjadi true, sedangkan hapusTugas() memakai array_splice() untuk mencabut elemen pada indeks tertentu sehingga indeks array tetap rapat. Keduanya mengembalikan null bila ID tidak ditemukan — sinyal bagi pemanggil untuk menolak perintah:
<?php
require_once __DIR__ . '/main.php';
$tugas = [
['id' => 1, 'judul' => 'Belajar PHP dasar', 'selesai' => false],
['id' => 2, 'judul' => 'Belajar OOP', 'selesai' => false],
];
$hasil = tandaiSelesai($tugas, 1);
tampilkanTugas($hasil);
$hasil = hapusTugas($hasil, 1);
tampilkanTugas($hasil);
var_dump(cariTugas($hasil, 1));
var_dump(hapusTugas($hasil, 99));Output yang Dihasilkan:
Daftar Tugas:
1. [x] Belajar PHP dasar
2. [ ] Belajar OOP
Daftar Tugas:
2. [ ] Belajar OOP
NULL
NULLPerhatikan urutan keluaran di atas: tugas 1 menerima tanda [x], lalu hilang sepenuhnya setelah dihapus. Dua baris NULL menegaskan bahwa pencarian ID 1 setelah penghapusan dan penghapusan ID 99 sama-sama tidak menemukan sasaran.
Menyatukan Operasi ke Perintah CLI #
Fungsi jalankan() kini membawa daftar tugas dalam memori dan mengirimkannya ke fungsi perintah. Perintah tambah membaca judul dari $argv[2], mengubah daftar, lalu mencetak konfirmasi beserta daftar terbaru:
<?php
require_once __DIR__ . '/main.php';
$kode = jalankan(['main.php', 'tambah', 'Belajar PHP dasar']);
echo "exit code: $kode\n";Output yang Dihasilkan:
Tugas ditambahkan: [1] Belajar PHP dasar
Daftar Tugas:
1. [ ] Belajar PHP dasar
exit code: 0Karena jalankan() menerima $argv sebagai parameter biasa, kita bisa mensimulasikan pemanggilan CLI tanpa memulai proses baru — teknik yang dipakai semua blok contoh di halaman ini dan nanti menjadi fondasi pengujian otomatis pada Bagian 5.
Menjalankan Program #
Dari direktori bagian ini, mari kita jalankan perintah-perintahnya sungguhan:
$ php main.php tambah "Belajar PHP dasar"Tugas ditambahkan: [1] Belajar PHP dasar
Daftar Tugas:
1. [ ] Belajar PHP dasar$ php main.php listBelum ada tugas.$ php main.php selesai 1
$ echo $?Error: tugas dengan ID 1 tidak ditemukan.
1Keterbatasan: Daftar Hilang Saat Program Berakhir #
Hasil list di atas kosong meski kita baru saja menambah tugas. Penyebabnya: variabel $tugas hidup di memori proses, dan memori itu dibebaskan begitu main.php selesai. Kita bisa melihatnya langsung dalam satu eksekusi:
<?php
require_once __DIR__ . '/main.php';
jalankan(['main.php', 'tambah', 'Belajar PHP dasar']);
echo "---\n";
jalankan(['main.php', 'list']);Output yang Dihasilkan:
Tugas ditambahkan: [1] Belajar PHP dasar
Daftar Tugas:
1. [ ] Belajar PHP dasar
---
Belum ada tugas.Blok di atas menunjukkan dua panggilan jalankan() yang berdiri sendiri — pemanggilan kedua tidak mewarisi apa pun dari pemanggilan pertama karena $tugas selalu dibuat ulang sebagai [] di dalam fungsi. Aplikasi daftar tugas yang sesungguhnya harus mengingat datanya lintas eksekusi, dan itulah pekerjaan Bagian 3: memindahkan daftar ke berkas JSON di disk.
Apa yang Berubah dari Bagian 1 #
Pesan penggunaan kini memuat kelima perintah beserta contohnya, bukan hanya list. Perintah tambah, selesai, dan hapus sudah dieksekusi sungguhan dengan seluruh operasi array pendukungnya, dan setiap kegagalan (argumen hilang, ID tak ditemukan) mengembalikan exit code 1 dengan pesan yang jelas. Pesan error untuk perintah tak dikenal juga dipersingkat karena semua perintah kontrak kini benar-benar tersedia.
Ringkasan #
Tugas ternyata cukup dimodelkan sebagai array asosiatif, dan operasi-operasinya adalah fungsi murni yang menerima daftar lalu mengembalikan daftar baru — kebiasaan yang lahir dari perilaku salinan array PHP. Kerangka dispatch dari Bagian 1 tidak perlu diubah sama sekali; kita hanya memperluas cabang match dan mengalirkan data ke sana. Selanjutnya kita beri program ini ingatan: penyimpanan permanen berbasis JSON.
Referensi #
- Arrays — sintaks array asosiatif dan perilaku salinan.
- Array Functions
— daftar fungsi array termasuk
array_splicedanarray_key_last.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
main.php
Unduh berkas<?php
declare(strict_types=1);
/**
* Pengelola Daftar Tugas — Bagian 2: Operasi Tugas.
*
* Perintah tambah, selesai, dan hapus kini berfungsi. Namun daftar
* tugas hanya hidup di memori: setiap eksekusi dimulai dari daftar
* kosong. Penyimpanan permanen dikerjakan pada Bagian 3.
*/
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
php main.php tambah <judul> Tambah tugas baru
php main.php selesai <id> Tandai tugas sebagai selesai
php main.php hapus <id> Hapus tugas
Contoh:
php main.php tambah "Belajar PHP dasar"
php main.php selesai 1
php main.php hapus 2
TEKS;
return KELUAR_OK;
}
// ---------------------------------------------------------------------------
// Operasi murni atas array tugas — tanpa I/O, mudah diuji terpisah.
// ---------------------------------------------------------------------------
/** Bentuk satu tugas baru dengan status belum selesai. */
function tugasBaru(int $id, string $judul): array
{
return ['id' => $id, 'judul' => $judul, 'selesai' => false];
}
/** Hitung ID untuk tugas berikutnya: selalu terbesar + 1. */
function idBerikutnya(array $tugas): int
{
$terbesar = 0;
foreach ($tugas as $t) {
$terbesar = max($terbesar, $t['id']);
}
return $terbesar + 1;
}
/** Kembalikan daftar tugas baru yang sudah berisi tugas tambahan. */
function tambahTugas(array $tugas, string $judul): array
{
$tugas[] = tugasBaru(idBerikutnya($tugas), $judul);
return $tugas;
}
/** Cari satu tugas berdasarkan ID; null bila tidak ada. */
function cariTugas(array $tugas, int $id): ?array
{
foreach ($tugas as $t) {
if ($t['id'] === $id) {
return $t;
}
}
return null;
}
/** Kembalikan daftar baru dengan status selesai true; null bila ID tidak ada. */
function tandaiSelesai(array $tugas, int $id): ?array
{
foreach ($tugas as $i => $t) {
if ($t['id'] === $id) {
$tugas[$i]['selesai'] = true;
return $tugas;
}
}
return null;
}
/** Kembalikan daftar baru tanpa tugas tersebut; null bila ID tidak ada. */
function hapusTugas(array $tugas, int $id): ?array
{
foreach ($tugas as $i => $t) {
if ($t['id'] === $id) {
array_splice($tugas, $i, 1);
return $tugas;
}
}
return null;
}
/** Cetak daftar tugas ke layar dengan format centang. */
function tampilkanTugas(array $tugas): void
{
if ($tugas === []) {
echo "Belum ada tugas.\n";
return;
}
echo "Daftar Tugas:\n";
foreach ($tugas as $t) {
printf(" %d. [%s] %s\n", $t['id'], $t['selesai'] ? 'x' : ' ', $t['judul']);
}
}
// ---------------------------------------------------------------------------
// Perintah CLI — tiap fungsi mengembalikan exit code.
// ---------------------------------------------------------------------------
function perintahList(array $tugas): int
{
tampilkanTugas($tugas);
return KELUAR_OK;
}
function perintahTambah(array $argv, array $tugas): int
{
$judul = $argv[2] ?? null;
if ($judul === null) {
printf("Error: judul tugas wajib diisi. Contoh: php main.php tambah \"Belajar PHP\"\n");
return KELUAR_GAGAL;
}
$tugas = tambahTugas($tugas, $judul);
$baru = $tugas[array_key_last($tugas)];
printf("Tugas ditambahkan: [%d] %s\n\n", $baru['id'], $baru['judul']);
tampilkanTugas($tugas);
return KELUAR_OK;
}
function perintahSelesai(array $argv, array $tugas): int
{
$id = $argv[2] ?? null;
if ($id === null) {
printf("Error: ID tugas wajib diisi. Contoh: php main.php selesai 1\n");
return KELUAR_GAGAL;
}
$hasil = tandaiSelesai($tugas, (int) $id);
if ($hasil === null) {
printf("Error: tugas dengan ID %d tidak ditemukan.\n", (int) $id);
return KELUAR_GAGAL;
}
$terkait = cariTugas($hasil, (int) $id);
printf("Tugas ditandai selesai: [%d] %s\n\n", $terkait['id'], $terkait['judul']);
tampilkanTugas($hasil);
return KELUAR_OK;
}
function perintahHapus(array $argv, array $tugas): int
{
$id = $argv[2] ?? null;
if ($id === null) {
printf("Error: ID tugas wajib diisi. Contoh: php main.php hapus 1\n");
return KELUAR_GAGAL;
}
$terhapus = cariTugas($tugas, (int) $id);
$hasil = hapusTugas($tugas, (int) $id);
if ($hasil === null) {
printf("Error: tugas dengan ID %d tidak ditemukan.\n", (int) $id);
return KELUAR_GAGAL;
}
printf("Tugas dihapus: [%d] %s\n\n", $terhapus['id'], $terhapus['judul']);
tampilkanTugas($hasil);
return KELUAR_OK;
}
function perintahTidakDikenal(string $perintah): int
{
printf("Error: perintah tidak dikenal: %s\n\n", $perintah);
perintahBantuan();
return KELUAR_GAGAL;
}
/**
* Titik masuk program. Daftar tugas hidup di memori dan
* selalu kosong di awal setiap eksekusi.
*/
function jalankan(array $argv): int
{
$perintah = $argv[1] ?? '';
if ($perintah === '') {
return perintahBantuan();
}
$tugas = [];
return match ($perintah) {
'list' => perintahList($tugas),
'tambah' => perintahTambah($argv, $tugas),
'selesai' => perintahSelesai($argv, $tugas),
'hapus' => perintahHapus($argv, $tugas),
default => perintahTidakDikenal($perintah),
};
}
// Jalankan hanya bila dieksekusi langsung sebagai skrip CLI,
// bukan saat di-include dari berkas lain (blok contoh, pengujian).
if (PHP_SAPI === 'cli' && isset($argv[0]) && realpath($argv[0]) === __FILE__) {
exit(jalankan($argv));
}