Symfony 8 di 2026: Fitur Baru, PHP 8.4 Lazy Objects, dan Pertanyaan Wawancara
Symfony 8 menghadirkan lazy objects bawaan, form multi-langkah, invokable commands, serta komponen JSON baru. Pembahasan mendalam tentang fitur-fitur penting untuk produksi dan persiapan wawancara teknis.

Symfony 8, yang dirilis pada November 2025, menghapus seluruh deprecation dari siklus 7.x dan menghadirkan rangkaian fitur yang sama dengan Symfony 7.4 — namun dengan persyaratan minimum PHP 8.4. Persyaratan ini membuka jalan bagi penggunaan native lazy objects, property hooks, dan HTML5 parser baru, tiga fitur tingkat bahasa yang kini dimanfaatkan secara internal oleh framework. Artikel ini membahas fitur-fitur yang mengubah alur kerja pengembangan sehari-hari, berdampak pada persiapan wawancara teknis, dan perlu diperhatikan saat melakukan upgrade ke produksi.
Symfony 8.0 mensyaratkan PHP 8.4+, menghadirkan form multi-langkah bawaan (AbstractFlowType), console command yang dapat dipanggil langsung (invokable) dengan atribut #[Argument] dan #[Option], tiga komponen JSON/ObjectMapper baru, serta menggantikan pembuatan proxy code dengan native lazy objects PHP 8.4 di seluruh DependencyInjection dan Doctrine.
Native Lazy Objects Menggantikan Proxy Code Generation
PHP 8.4 memperkenalkan lazy objects di tingkat engine melalui ReflectionClass::newLazyGhost() dan ReflectionClass::newLazyProxy(). Symfony 8 memanfaatkan fitur ini secara langsung: komponen DependencyInjection tidak lagi membuat kelas proxy untuk lazy services. Sebagai gantinya, framework membuat ghost objects yang melakukan inisialisasi saat property pertama kali diakses.
Dampak praktisnya sangat signifikan. Kelas final dan readonly — yang sebelumnya tidak kompatibel dengan lazy loading berbasis proxy milik Symfony — kini dapat digunakan tanpa solusi alternatif. Doctrine juga mendapat manfaat serupa: entity proxy tidak lagi memerlukan code generation, menghilangkan beban pemeliharaan yang bertahan selama lebih dari satu dekade.
namespace App\Service;
use Symfony\Component\DependencyInjection\Attribute\Lazy;
#[Lazy]
final readonly class HeavyReportGenerator
{
public function __construct(
private DatabaseConnection $db,
private PdfEngine $pdf,
private CacheInterface $cache,
) {
// Constructor runs only when a method is actually called
}
public function generate(int $reportId): string
{
$data = $this->db->fetchReport($reportId);
return $this->pdf->render($data);
}
}Atribut #[Lazy] menandai service untuk diinstansiasi sebagai ghost object. Container menyuntikkan sebuah shell yang tampak identik dengan HeavyReportGenerator. Constructor — beserta tiga dependensi yang diinjeksi — hanya dieksekusi ketika generate() dipanggil. Untuk service yang digunakan secara kondisional (misalnya pembuatan laporan yang dipicu oleh aksi admin tertentu), pendekatan ini menghilangkan koneksi database dan alokasi memori yang tidak diperlukan pada setiap request.
Variasi #[Autowire(lazy: true)] memungkinkan lazy injection pada sisi pemanggil tanpa mengubah kelas service itu sendiri:
namespace App\Controller;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class DashboardController
{
public function __construct(
#[Autowire(lazy: true)]
private HeavyReportGenerator $reportGenerator,
) {}
}Dalam konteks wawancara, pertanyaan tentang perbedaan ghost objects dan virtual proxies sering muncul. Ghost objects melakukan inisialisasi instance asli secara langsung di tempat (in-place). Virtual proxies mendelegasikan ke instance terpisah yang telah diinisialisasi sepenuhnya. Symfony secara default menggunakan ghost objects kecuali jika factory terlibat, dalam kasus tersebut framework secara otomatis beralih ke proxy.
Form Multi-Langkah dengan AbstractFlowType
Sebelum Symfony 8, form multi-langkah memerlukan bundle pihak ketiga seperti CraueFormFlowBundle. Kini framework menyediakan AbstractFlowType — sebuah mesin form flow bawaan dengan validasi per langkah, percabangan kondisional, dan navigasi terintegrasi.
namespace App\Form;
use Symfony\Component\Form\Flow\AbstractFlowType;
use Symfony\Component\Form\Flow\FormFlowBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserSignUpType extends AbstractFlowType
{
public function buildFormFlow(FormFlowBuilderInterface $builder, array $options): void
{
$builder->addStep('personal', UserPersonalType::class);
$builder->addStep('professional', UserProfessionalType::class);
$builder->addStep('account', UserAccountType::class);
$builder->add('navigator', NavigatorFlowType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => UserSignUp::class,
'step_property_path' => 'currentStep',
]);
}
}Setiap nama langkah berfungsi sekaligus sebagai validation group. Kelas data UserSignUp menggunakan #[Valid] dengan constraint berdasarkan grup untuk memvalidasi hanya langkah yang sedang aktif:
namespace App\DTO;
use Symfony\Component\Validator\Constraints as Assert;
class UserSignUp
{
public function __construct(
#[Assert\Valid(groups: ['personal'])]
public Personal $personal = new Personal(),
#[Assert\Valid(groups: ['professional'])]
public Professional $professional = new Professional(),
#[Assert\Valid(groups: ['account'])]
public Account $account = new Account(),
public string $currentStep = 'personal',
) {}
}Controller-nya mengikuti pola penanganan form standar Symfony. Method isFinished() mengembalikan true hanya setelah langkah terakhir lolos validasi:
#[Route('/signup')]
public function __invoke(Request $request): Response
{
$flow = $this->createForm(UserSignUpType::class, new UserSignUp())
->handleRequest($request);
if ($flow->isSubmitted() && $flow->isValid() && $flow->isFinished()) {
$this->userService->register($flow->getData());
return $this->redirectToRoute('app_signup_success');
}
return $this->render('signup/flow.html.twig', [
'form' => $flow->getStepForm(),
]);
}Tombol navigasi (NextFlowType, PreviousFlowType, FinishFlowType, ResetFlowType) mendukung rendering kondisional melalui include_if, melompati langkah dengan skip, dan navigasi langsung dengan back_to. Fitur-fitur ini mencakup sebagian besar pola wizard di dunia nyata tanpa memerlukan pengelolaan state menggunakan JavaScript khusus.
Siap menguasai wawancara Symfony Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Invokable Commands dengan Input Attributes
Console command tidak lagi mengharuskan pengembang untuk meng-extend base class Command atau meng-override method configure(). Method __invoke() menerima argument dan option secara langsung melalui atribut PHP.
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\Option;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: 'app:create-user',
description: 'Create a new user account',
)]
class CreateUserCommand
{
public function __invoke(
SymfonyStyle $io,
#[Argument(description: 'The username for the new account')]
string $username,
#[Argument(description: 'The email address')]
string $email,
#[Option(shortcut: 'r', description: 'Role to assign')]
string $role = 'ROLE_USER',
#[Option(description: 'Activate immediately')]
bool $activate = false,
): int {
// User creation logic
$io->success(sprintf('User "%s" created with role %s.', $username, $role));
return Command::SUCCESS;
}
}Symfony 8 menambahkan dukungan backed enum untuk argument dan option. Input berupa string secara otomatis dikonversi ke enum case yang sesuai:
enum CloudRegion: string {
case UsEast = 'us-east';
case UsWest = 'us-west';
case EuWest = 'eu-west';
}
// In the command
public function __invoke(
SymfonyStyle $io,
#[Argument] CloudRegion $region,
#[Option] ?ServerSize $size = null,
): int {
$io->info(sprintf('Deploying to %s', $region->value));
return Command::SUCCESS;
}Untuk command dengan banyak parameter, #[MapInput] memetakan input ke sebuah DTO:
class DeployInput
{
#[Argument]
public CloudRegion $region;
#[Option]
public string $branch = 'main';
#[Option(shortcut: 'f')]
public bool $force = false;
}
// src/Command/DeployCommand.php
#[AsCommand(name: 'app:deploy')]
class DeployCommand
{
public function __invoke(
SymfonyStyle $io,
#[MapInput] DeployInput $input,
): int {
// Access $input->region, $input->branch, $input->force
return Command::SUCCESS;
}
}Pola ini menghilangkan kebutuhan akan boilerplate configure() + execute() dan membuat command dapat diuji secara langsung dengan mengkonstruksi DTO-nya.
Komponen JSON Streamer, JSON Path, dan ObjectMapper
Tiga komponen standalone baru hadir bersama Symfony 8:
JsonStreamer memproses payload JSON berukuran besar tanpa memuat seluruh dokumen ke dalam memori. Untuk API yang menangani respons berskala megabyte — ekspor data massal, feed analitik, ingestion log — komponen ini menghindari batas memori dari json_decode().
JsonPath mengimplementasikan subset dari RFC 9535 untuk menavigasi struktur JSON bersarang. Alih-alih mendekode seluruh respons dan melintasi array secara manual, ekspresi path mengekstrak data target secara langsung.
ObjectMapper mengonversi antara DTO dan array/JSON menggunakan atribut PHP, menggantikan logika hidrasi yang ditulis secara manual. Dikombinasikan dengan komponen Serializer, komponen ini mencakup seluruh siklus hidup pemetaan request/response API.
Pertanyaan wawancara Symfony di tahun 2026 sering membahas lazy objects (ghost vs. proxy), siklus hidup AbstractFlowType, dan pergeseran dari configure() ke invokable commands. Memahami pola-pola ini menunjukkan keakraban dengan versi framework terkini, bukan sekadar pengetahuan versi lama.
Peningkatan Keamanan dan Developer Experience
Perlindungan CSRF tidak lagi memerlukan sesi di sisi server. Implementasi CSRF stateless yang baru kompatibel dengan HTTP caching, menjadikannya layak untuk arsitektur API-first dan halaman yang di-cache CDN.
Komponen Messenger mendukung penandatanganan pesan (message signing) — tanda tangan kriptografis pada payload mencegah manipulasi antara producer dan consumer. Untuk sistem di mana integritas pesan sangat penting (pemrosesan pembayaran, audit trail), fitur ini menggantikan middleware penandatanganan khusus.
Constraint validasi baru mencakup charset, alamat MAC, nomor minggu ISO, jumlah kata, sintaks YAML, slug, template Twig, dan file video. Constraint #[Slug] saja sudah menghilangkan kebutuhan akan custom validator yang umum digunakan.
Security voters kini menjelaskan keputusannya di profiler. Proses debugging logika otorisasi — yang sebelumnya merupakan proses menebak voter mana yang menolak akses — kini menjadi pencarian langsung di toolbar profiler Symfony.
Symfony 8.0 menghapus semua deprecation dari siklus 7.x, menghilangkan 13.202 baris kode backward-compatibility. Pendekatan yang disarankan: upgrade ke Symfony 7.4 terlebih dahulu, jalankan php bin/phpunit --display-deprecations, perbaiki setiap peringatan, lalu beralih ke 8.0. Melewatkan versi 7.4 berisiko menimbulkan runtime error dari API yang sudah dihapus.
Property Hooks PHP 8.4 dalam Konteks Symfony
Property hooks (get dan set yang didefinisikan langsung pada property kelas) terintegrasi secara alami dengan ekosistem Symfony. Entity Doctrine dapat menggunakan hooks untuk computed property. Form type dapat memanfaatkan hooks untuk transformasi data. Constraint validasi berfungsi pada property yang menggunakan hooks tanpa modifikasi.
class Product
{
public string $name {
set(string $value) {
$this->name = trim($value);
}
}
public float $price {
set(float $value) {
if ($value < 0) {
throw new \InvalidArgumentException('Price cannot be negative');
}
$this->price = $value;
}
}
public float $priceWithTax {
get => $this->price * 1.20;
}
}Property hooks mengurangi kebutuhan akan pasangan getter/setter dan memindahkan penegakan invarian ke dalam definisi property itu sendiri. Dalam Symfony forms, hal ini berarti lebih sedikit boilerplate transformer. Dalam entity Doctrine, nilai yang dihitung tetap berada dekat dengan data yang menjadi dependensinya.
Pertanyaan Wawancara yang Perlu Dipersiapkan
Symfony 8 menggeser materi yang diuji oleh pewawancara. Topik-topik berikut muncul secara reguler dalam persiapan wawancara Symfony:
- Lazy objects: Jelaskan perbedaan antara ghost objects dan virtual proxies. Kapan Symfony memilih salah satu di atas yang lain? Mengapa PHP 8.4 memungkinkan service
final readonlyuntuk mendukung lazy loading? - Form multi-langkah: Bagaimana
AbstractFlowTypemenangani validasi per langkah? Apa peranstep_property_path? Bagaimana langkah kondisional bekerja? - Invokable commands: Apa yang menggantikan
configure()pada invokable commands? Bagaimana cara kerja#[MapInput]? Apa aturan untuk default pada#[Option]? - Komponen baru: Kapan JsonStreamer lebih tepat digunakan dibanding
json_decode()? Masalah apa yang dipecahkan ObjectMapper yang tidak ditangani oleh Serializer? - Strategi upgrade: Mengapa upgrade ke 7.4 sebelum 8.0 disarankan? Apa implikasi penghapusan 13.202 baris kode deprecation terhadap backward compatibility?
Latih topik-topik ini dengan kode nyata. Modul console commands Symfony dan modul Doctrine advanced mencakup area yang paling sering diuji.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Kesimpulan
- Symfony 8 mensyaratkan PHP 8.4 dan sepenuhnya mengadopsi native lazy objects, menghilangkan proxy code generation untuk DI container maupun Doctrine ORM
AbstractFlowTypemenggantikan bundle pihak ketiga untuk form multi-langkah, dengan validation group per langkah dan tombol navigasi bawaan- Invokable commands dengan
#[Argument],#[Option], dan#[MapInput]menghapus boilerplate serta mendukung backed enum dan DTO - Tiga komponen baru (JsonStreamer, JsonPath, ObjectMapper) menangani pemrosesan JSON dan pemetaan objek tanpa dependensi eksternal
- CSRF stateless, penandatanganan pesan, debugging security voter, dan lebih dari 20 constraint validasi baru memperkuat aspek keamanan dan developer experience
- Property hooks dari PHP 8.4 terintegrasi secara transparan dengan entity Doctrine, form Symfony, dan constraint validasi
- Jalur upgrade melalui Symfony 7.4: perbaiki semua deprecation di sana sebelum beralih ke 8.0
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Tag
Bagikan
