© 2026 Laravel

Bản chất của PHP: Một cuộc dạo chơi trong Zend Engine

5 phút đọc
#php #internals #zend-engine #performance #memory-management #jit

Nhiều lập trình viên dùng PHP hàng ngày nhưng coi nó như một “hộp đen”. Hiểu về Zend Engine không chỉ giúp bạn giải mã hộp đen đó, mà còn giúp bạn viết code tối ưu đến từng byte bộ nhớ.

#1. Vòng đời của một đoạn mã PHP

Khi bạn chạy một file PHP, Zend Engine thực hiện qua 4 giai đoạn chính:

  1. Scanning (Lexing): Engine đọc file source code và chia nhỏ nó thành các đơn vị có nghĩa gọi là Tokens (ví dụ: T_VARIABLE, T_ECHO).
  2. Parsing: Engine kiểm tra xem các Tokens đó có tuân thủ đúng cú pháp không và xây dựng nên một cây cấu trúc gọi là AST (Abstract Syntax Tree).
  3. Compilation: AST được biên dịch thành Opcodes. Đây là các chỉ thị máy mức thấp mà máy ảo Zend VM có thể hiểu được. Nếu bạn bật Opcache, các Opcodes này sẽ được lưu vào RAM cho các request sau.
  4. Execution: Zend VM thực thi các Opcodes và trả về kết quả.

#2. Bước ngoặt PHP 7: Sự trỗi dậy của Zval

Trong PHP 5, mọi biến (zval) là một cấu trúc dữ liệu phức tạp được cấp phát trên bộ nhớ Heap. Việc này tốn nhiều RAM và làm khổ hệ thống dọn rác (Garbage Collection).

Từ PHP 7+, cấu trúc zval được thiết kế lại hoàn toàn:

  • Kích thước giảm từ 24 bytes xuống còn 16 bytes.
  • Các giá trị đơn giản như int, float, bool được lưu trực tiếp ngay trong zval thay vì trỏ ra Heap.
  • Chỉ các kiểu dữ liệu phức tạp (Object, Array lớn, String dài) mới cần dùng Heap. Đây là lý do tại sao PHP 7 nhanh gấp đôi PHP 5 mà lại tốn ít RAM hơn.

#3. Copy-on-Write (COW): Quản lý bộ nhớ thông minh

PHP sử dụng cơ chế COW để tránh việc copy dữ liệu vô tội vạ.

$a = [1, 2, 3];
$b = $a; // $a và $b cùng trỏ vào 1 vùng nhớ, refcount = 2
$b[] = 4; // Chỉ khi bạn thay đổi $b, PHP mới thực hiện copy thật sự.

Điều này giúp việc truyền mảng lớn vào hàm (function(array $data)) cực kỳ nhanh vì PHP chỉ truyền con trỏ.

#4. PHP 8 và JIT (Just-In-Time)

JIT là bước tiến lớn nhất của PHP 8. Thay vì để máy ảo Zend VM thông dịch Opcodes, JIT sẽ biên dịch các đoạn code chạy thường xuyên (hot code) thành mã máy CPU thực sự.

  • Lợi ích: Cực kỳ mạnh cho các tác vụ tính toán (CPU-bound) như xử lý ảnh, AI, mã hóa.
  • Lưu ý: Với các app Web thông thường (IO-bound - đợi DB/Mạng), JIT không mang lại nhiều khác biệt vì nút thắt nằm ở Database chứ không phải ở PHP.

#5.Câu hỏi nhanh

Câu hỏi: Tại sao việc lạm dụng tham chiếu (&$variable) trong PHP 7+ đôi khi lại làm code chạy chậm hơn so với truyền giá trị thông thường?

Trả lời: Vì tham chiếu làm hỏng cơ chế Copy-on-Write. Khi bạn dùng tham chiếu, PHP buộc phải tạo ra một cấu trúc quản lý phức tạp hơn (Reference object) để theo dõi các biến. Nó mất đi khả năng tối ưu hóa trỏ chung vùng nhớ. Trừ khi bạn chắc chắn cần thay đổi giá trị gốc của một biến rất lớn bên trong hàm, hãy để PHP tự lo việc tối ưu bộ nhớ qua cơ chế truyền giá trị mặc định.

#6. Kết luận

PHP ngày nay đã thoát xác khỏi hình ảnh một ngôn ngữ “chậm chạp”. Với sự tối ưu tuyệt vời của Zend Engine, PHP 8 vẫn là lựa chọn hàng đầu cho các hệ thống Backend hiện đại.

Bài viết liên quan