1. Ekspresi Reguler di PHP dengan Ekstensi PCRE2 (preg_*)
Di PHP, ekspresi reguler menggunakan mesin **PCRE2 (Perl Compatible Regular Expressions)** di mana pola selalu diapit oleh karakter pembatas (delimiter, biasanya garis miring /pola/flags atau tanda pagar #pola#flags jika pola mengandung banyak garis miring URL):
<?php
declare(strict_types=1);
// 1. preg_match(): Mengembalikan 1 jika cocok, 0 jika tidak cocok, atau false jika terjadi galat
// Gunakan Named Subpatterns (?<nama>...) dan flag 'u' (UTF-8 mode)!
$polaKodeKelas = '/^(?<bidang>[a-z]+)-(?<nomor>\d{3})$/u';
if (preg_match($polaKodeKelas, 'backend-104', $tangkapan) === 1) {
echo "Bidang: {$tangkapan['bidang']}, Nomor: {$tangkapan['nomor']}\n";
// Bidang: backend, Nomor: 104
}
// 2. preg_replace_callback(): Mengubah teks yang cocok menggunakan fungsi callback yang aman!
$teksMarkdown = 'Baca modul [[01-cara-web-bekerja]] dan [[02-struktur-dokumen-html]].';
$teksHtml = preg_replace_callback(
'/\[\[(?<slug>[a-z0-9-]+)\]\]/u',
static fn(array $m): string => sprintf(
'<a href="/materi/%s">%s</a>',
htmlspecialchars($m['slug'], ENT_QUOTES, 'UTF-8'),
htmlspecialchars($m['slug'], ENT_QUOTES, 'UTF-8'),
),
$teksMarkdown,
);
echo $teksHtml;
^ dan $ vs \A dan \z!Jika Anda menggunakan flag multiline (m), atau bahkan tanpa flag m, jangkar akhir $ di PCRE secara bawaan masih mengizinkan satu karakter baris baru (\n) di paling ujung string! Untuk validasi keamanan ketat yang memastikan tidak ada baris baru yang menyelundup di akhir string, gunakan \A (awal mutlak string) dan \z (akhir mutlak string), atau tambahkan flag D (PCRE_DOLLAR_ENDONLY)!
2. Mengenal PHP Attributes (#[...] — Sejak PHP 8.0 hingga 8.5)
Di pelajaran sebelumnya, kita telah memakai atribut bawaan PHP seperti #[\Override] dan #[\NoDiscard]; atribut bawaan lain seperti #[\Deprecated] serta atribut PHPUnit seperti #[Test] dan #[DataProvider] akan ditemui pada pelajaran berikutnya.
Apa sebenarnya Attributes (#[...]) itu? Sebelum PHP 8.0, pengembang terpaksa menulis konfigurasi metadata di dalam komentar teks /** @Route("/kelas") */ (docblock annotations) lalu mengurainya dengan regex yang lambat dan rawan salah ketik. Sejak PHP 8.0, Attributes menyediakan metadata terstruktur kelas satu di tingkat sintaks bahasa PHP yang dapat ditempelkan pada class, metode, fungsi, properti, parameter, maupun konstanta!
3. Membuat Custom Attribute Sendiri dan Membacanya dengan Reflection API
Mari kita lihat bagaimana framework modern (seperti Symfony atau Laravel) mendaftarkan rute URL atau izin akses secara otomatis menggunakan Custom Attribute dan ReflectionClass / ReflectionMethod:
<?php
declare(strict_types=1);
namespace Kodeloka\Routing;
use Attribute;
use ReflectionClass;
use ReflectionMethod;
// 1. Mendefinisikan class Attribute kita sendiri:
// Batasi agar atribut #[Rute] hanya boleh dipasang pada METODE (TARGET_METHOD)
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
readonly class Rute
{
public function __construct(
public string $jalur,
public string $metodeHttp = 'GET',
) {}
}
// 2. Memasang atribut #[Rute] pada metode di dalam Controller:
final class KelasController
{
#[Rute(jalur: '/kelas', metodeHttp: 'GET')]
public function daftarKelas(): string
{
return 'Menampilkan daftar semua kelas Kodeloka';
}
#[Rute(jalur: '/kelas/daftar', metodeHttp: 'POST')]
public function prosesPendaftaran(): string
{
return 'Memproses pendaftaran peserta baru';
}
}
// 3. Membaca metadata Attribute saat runtime menggunakan Reflection API!
function ekstrakDaftarRute(string $namaClassController): array
{
$refleksiKelas = new ReflectionClass($namaClassController);
$petaRute = [];
foreach ($refleksiKelas->getMethods(ReflectionMethod::IS_PUBLIC) as $metode) {
// Mengambil seluruh atribut #[Rute] yang menempel pada metode ini
$atributRute = $metode->getAttributes(Rute::class);
foreach ($atributRute as $attr) {
/** @var Rute $instansRute */
$instansRute = $attr->newInstance(); // Menginstansiasi objek Rute!
$petaRute[] = [
'http' => $instansRute->metodeHttp,
'jalur' => $instansRute->jalur,
'target' => $namaClassController . '::' . $metode->getName(),
];
}
}
return $petaRute;
}
print_r(ekstrakDaftarRute(KelasController::class));
(Catatan: Sejak PHP 8.5, parameter di dalam atribut #[...] bahkan sudah dapat menerima static closures dan first-class callables secara langsung!)
Latihan Praktik: Validator Objek Otomatis Berbasis Atribut #[WajibDiisi] dan #[PanjangTeks]
Buatlah berkas validator-atribut.php dan jalankan dengan php validator-atribut.php:
- Buat atribut
#[Attribute(Attribute::TARGET_PROPERTY)] readonly class PanjangTeksdengan propertipublic int $mindanpublic int $maks. - Buat DTO
class InputKursusyang propertinya dipasangi#[PanjangTeks(min: 5, maks: 50)] public string $judul. - Buat fungsi
validasiObjek(object $dto): arrayyang menggunakannew ReflectionClass($dto)untuk memeriksa semua properti yang memiliki atributPanjangTeksdan mengembalikan daftar pesan kesalahan jika panjangnya tidak sesuai!