Dulu waktu pertama kali pindah dari PHP 7.x ke PHP 8, saya agak skeptis. Kode lama masih jalan, kenapa harus repot upgrade? Ternyata begitu coba fitur-fitur barunya, rasanya kayak naik dari motor ke mobil semuanya lebih smooth dan efisien. Sekarang kalau nemu kode pakai cara lama yang bisa disederhanakan pakai fitur PHP 8.x, langsung kepengen refactor.
PHP 8.0, 8.1, 8.2, dan 8.3 masing-masing bawa perubahan signifikan yang bikin kode lebih aman, lebih cepat, dan lebih enak dibaca. Di sini saya bakal bahas fitur-fitur yang paling sering saya pakai di project sehari-hari, lengkap dengan contoh nyata.
Salah satu masalah klasik di PHP lama: function dengan banyak parameter opsional. Mau skip beberapa parameter di tengah? Harus tetap nulis null atau default value-nya.
// PHP 7 harus nulis semua parameter meski cuma mau set yang terakhir
$html = str_replace('search', 'replace', $string, $count);
// PHP 8 bisa langsung sebut nama parameter yang mau diisi
$html = str_replace(
search: 'hello',
replace: 'world',
subject: $string
);
// Contoh di function sendiri
function createUser(
string $name,
string $email = '',
int $age = 0,
bool $active = true,
string $role = 'member'
): array {
return compact('name', 'email', 'age', 'active', 'role');
}
// Skip email dan age, langsung set active dan role
$user = createUser(
name: 'Budi',
active: false,
role: 'admin'
);
Ini sangat membantu kalau kamu punya function dengan banyak parameter opsional. Kode jadi lebih jelas karena pembaca langsung tahu parameter mana yang diisi.
match itu versi upgrade dari switch. Return value langsung, strict comparison (pakai ===), dan syntax-nya lebih ringkas.
// PHP 7 switch, ribet
$statusText = '';
switch ($statusCode) {
case 200:
case 301:
$statusText = 'OK';
break;
case 404:
$statusText = 'Not Found';
break;
case 500:
$statusText = 'Server Error';
break;
default:
$statusText = 'Unknown';
}
// PHP 8 match, simpel
$statusText = match($statusCode) {
200, 301 => 'OK',
404 => 'Not Found',
500 => 'Server Error',
default => 'Unknown',
};
// Bisa juga dengan expression
$size = match(true) {
$bytes < 1024 => $bytes . ' B',
$bytes < 1048576 => round($bytes / 1024, 1) . ' KB',
$bytes < 1073741824 => round($bytes / 1048576, 1) . ' MB',
default => round($bytes / 1073741824, 2) . ' GB',
};
Yang bikin match lebih aman: dia pakai strict comparison. Jadi match(0) tidak akan match dengan string 'hello' masalah yang sering terjadi di switch karena loose comparison.
PHP 8.0 introduce Union Types, dan 8.1 nambah Intersection Types. Ini bikin type declaration lebih fleksibel tapi tetap ketat.
// Union Types parameter bisa tipe A ATAU tipe B
function formatNumber(int|float $number): string {
return number_format($number, 2, '.', ',');
}
function processId(int|string $id): void {
// Kalau string, convert ke int dulu
$id = is_string($id) ? (int) $id : $id;
echo "Processing ID: {$id}";
}
// Intersection Types (PHP 8.1) harus implement SEMUA interface
interface Loggable {
public function toLog(): string;
}
interface Cacheable {
public function getCacheKey(): string;
}
function store(Loggable&Cacheable $item): void {
echo $item->toLog();
echo $item->getCacheKey();
}
// DNF Types (PHP 8.2) kombinasi union dan intersection
function handle((Countable&Iterator)|array $items): void {
// Bisa array ATAU object yang implement Countable DAN Iterator
}
Kalau kamu pakai IDE seperti PHPStorm, Union Types dan Intersection Types bikin autocomplete jadi lebih akurat. Dan kalau ada type mismatch, error langsung ketangkep sebelum runtime.
Sebelum PHP 8.1, kalau mau bikin tipe yang terbatas (misal status order), biasanya pakai class dengan konstanta. Sekarang ada enum yang purpose-built untuk ini.
// PHP 8.1 Backed Enum
enum OrderStatus: string {
case Pending = 'pending';
case Processing = 'processing';
case Shipped = 'shipped';
case Delivered = 'delivered';
case Cancelled = 'cancelled';
}
// Pakai di function
function updateStatus(OrderStatus $status): void {
echo "Order status: " . $status->value;
}
updateStatus(OrderStatus::Shipped); // OK
// updateStatus('shipped'); // Error! Type safety
// Enum bisa punya method
enum Color: string {
case Red = '#ff0000';
case Green = '#00ff00';
case Blue = '#0000ff';
public function label(): string {
return match($this) {
self::Red => 'Merah',
self::Green => 'Hijau',
self::Blue => 'Biru',
};
}
}
echo Color::Red->label(); // "Merah"
echo Color::Red->value; // "#ff0000"
Enum juga bisa di-serialize ke database tanpa masalah karena backed enum punya value yang bisa disimpan sebagai string atau integer.
PHP 8.1 bikin property yang cuma bisa diisi sekali cocok untuk immutable objects. PHP 8.2 extend ke seluruh class.
// Readonly Properties (PHP 8.1)
class UserDTO {
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly int $age,
) {}
}
$user = new UserDTO(name: 'Budi', email: '[email protected]', age: 25);
echo $user->name; // "Budi"
// $user->name = 'Joko'; // Error! Cannot modify readonly property
// Readonly Class (PHP 8.2) semua property jadi readonly
readonly class Point {
public function __construct(
public float $x,
public float $y,
public float $z = 0.0,
) {}
}
$p = new Point(1.0, 2.0, 3.0);
// $p->x = 5.0; // Error!
Ini bagus banget untuk DTOs (Data Transfer Objects) dan value objects. Kamu bisa jamin data tidak berubah setelah object dibuat.
Fibers di PHP 8.1 itu cooperative multitasking. Mirip dengan generator/yield, tapi lebih powerful. Ini yang dipakai framework kayak Swoole dan ReactPHP di balik layar.
$fiber = new Fiber(function(): void {
$value = Fiber::suspend('fiber pause di sini');
echo "Fiber lanjut dengan: {$value}\n";
});
// Mulai fiber
$result = $fiber->start();
echo "Output dari suspend: {$result}\n";
// Lanjutkan fiber dengan mengirim nilai
$fiber->resume('data dari luar');
// Contoh lebih praktis simulating async
class AsyncTask {
private Fiber $fiber;
public function __construct(callable $task) {
$this->fiber = new Fiber($task);
}
public function run(): mixed {
return $this->fiber->start();
}
public function continue(mixed $value = null): mixed {
return $this->fiber->resume($value);
}
}
$task = new AsyncTask(function() {
echo "Step 1: Fetching data...\n";
$data = Fiber::suspend('waiting for data');
echo "Step 2: Got {$data}\n";
return "Done!";
});
echo $task->run() . "\n"; // "waiting for data"
echo $task->continue('user_data') . "\n"; // "Done!"
Kalau kamu butuh benar-benar async di production, biasanya pakai library seperti AMP atau ReactPHP yang build di atas Fibers.
Fitur ini sebenarnya dari PHP 8.0, tapi belum semua orang pakai. Bisa bikin kode class jadi jauh lebih pendek.
// PHP 7 tulis property + assign di constructor, 12 baris
class Product {
private string $name;
private float $price;
private int $stock;
private bool $active;
public function __construct(string $name, float $price, int $stock, bool $active) {
$this->name = $name;
$this->price = $price;
$this->stock = $stock;
$this->active = $active;
}
}
// PHP 8 constructor promotion, 8 baris (hemat 4 baris!)
class Product {
public function __construct(
private string $name,
private float $price,
private int $stock,
private bool $active = true,
) {}
}
// Bisa dikombinasikan dengan readonly
class OrderItem {
public function __construct(
public readonly string $productName,
public readonly int $quantity,
public readonly float $unitPrice,
) {}
public function subtotal(): float {
return $this->quantity * $this->unitPrice;
}
}
PHP 8.0 punya nullsafe operator ?-> yang bikin chaining null checks lebih bersih.
// PHP 7 verbose null checking
$country = null;
if ($user !== null) {
if ($user->getAddress() !== null) {
if ($user->getAddress()->getCity() !== null) {
$country = $user->getAddress()->getCity()->getCountry();
}
}
}
// PHP 8 nullsafe operator
$country = $user?->getAddress()?->getCity()?->getCountry();
// Kombinasi dengan named arguments
class UserService {
public function findUser(int $id): ?User {
return $this->repository->findById($id);
}
}
$service = new UserService();
// Chain + named args
$name = $service?->findUser(id: 42)?->getProfile()?->displayName;
PHP 8.2 dan 8.3 bawa beberapa fitur kecil tapi berguna:
(A&B)|C#[\AllowDynamicProperties] secara eksplisitjson_decode + json_last_error
// json_validate (PHP 8.3) cek JSON valid tanpa decode
$jsonString = '{"name": "Budi", "age": 25}';
// Cara lama
$result = json_decode($jsonString);
$isValid = json_last_error() === JSON_ERROR_NONE;
// PHP 8.3 satu baris
$isValid = json_validate($jsonString); // true
// Typed Class Constants (PHP 8.3)
interface HasStatus {
const string STATUS_ACTIVE = 'active';
const string STATUS_INACTIVE = 'inactive';
}
// #[Override] Attribute (PHP 8.3)
class BaseRepository {
public function findById(int $id): ?object {
return null;
}
}
class UserRepository extends BaseRepository {
#[\Override]
public function findById(int $id): ?User {
return $this->model->find($id);
}
}
Salah satu use case named arguments yang paling sering saya pakai: built-in PHP functions yang punya banyak parameter.
// Tanpa named arguments harus ingat urutan parameter
$clean = filter_var($input, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
// Dengan named arguments lebih jelas
$clean = filter_var(
value: $input,
filter: FILTER_SANITIZE_EMAIL,
options: FILTER_FLAG_NO_ENCODE_QUOTES
);
// Array functions
$data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$chunked = array_chunk(
array: $data,
length: 3,
preserve_keys: true
);
// String functions
$truncated = mb_strimwidth(
string: $longText,
start: 0,
width: 100,
trim_marker: '...'
);
Kalau kamu masih di PHP 7.x dan mau upgrade, ini checklist yang biasa saya pakai:
phpcompatinfo atau phpstan level tinggi untuk scan kode lamacomposer updateeach(), create_function(), dan beberapa fungsi lain sudah dihapus
// Cek versi PHP saat ini
echo PHP_VERSION; // 8.3.x
// Cek fitur yang tersedia
if (version_compare(PHP_VERSION, '8.1.0', '>=')) {
echo "Enums tersedia!";
}
// composer.json set minimum PHP version
{
"require": {
"php": ">=8.1",
"laravel/framework": "^10.0"
}
}
Bukan cuma fitur, PHP 8.x juga bawa peningkatan performa yang signifikan berkat JIT compiler dan optimasi internal:
json_validate(), improved randomizer peningkatan kecil tapi konsistenUntuk web request biasa, perbedaan performa PHP 7.4 ke 8.3 sekitar 5-10%. Tapi kalau kamu punya long-running process (queue worker, websocket server), JIT compiler di PHP 8.x bisa kasih peningkatan sampai 20-30%.
Saran saya: kalau masih di PHP 7.4, segera upgrade ke minimal PHP 8.1. Support PHP 7.4 sudah end-of-life sejak November 2022 artinya tidak ada lagi security patch. PHP 8.1 pun minimal sampai akhir 2024 untuk security fixes.