Chuyện Gì Đang Xảy Ra
Trước khi PHP chạy bất kỳ dòng nào, nó đọc toàn bộ script từ đầu đến cuối và kiểm tra cú pháp. Gặp dấu chấm phẩy bị thiếu, dấu ngoặc chưa đóng, hay ký tự lạ — nó dừng lại ngay tại đó và ném ra lỗi Parse error. Script không bao giờ được thực thi.
Lỗi trông như thế này:
Parse error: syntax error, unexpected token "echo", expecting "," or ";" in /var/www/html/index.php on line 15
PHP đang nói: "Tôi đang chờ dấu phẩy hoặc dấu chấm phẩy để kết thúc câu lệnh trước, nhưng lại thấy echo." Điều quan trọng cần hiểu: vấn đề thực sự hầu như không bao giờ nằm ở dòng được báo cáo. Thường là dòng phía trên nó — nơi bạn bỏ sót phần chưa đóng.
Quy Trình Debug
1. Kiểm tra dòng phía trước dòng được báo cáo
Đi đến dòng 14 — một dòng trên dòng 15 được báo cáo. Chín lần trong mười, có một dấu chấm phẩy bị thiếu ngay tại đó.
<?php
// Dòng 14 — không có dấu chấm phẩy ở cuối
$message = "Hello, world"
echo $message; // Dòng 15 — PHP vấp ở đây
Thêm dấu chấm phẩy vào là xong:
$message = "Hello, world";
echo $message;
2. Chạy kiểm tra cú pháp PHP từ terminal
Bỏ việc đoán mò. Dùng php -l (lint) để lấy lỗi chính xác mà không cần thực sự chạy script:
php -l /var/www/html/index.php
File không có lỗi:
No syntax errors detected in /var/www/html/index.php
File có lỗi:
Parse error: syntax error, unexpected token "echo", expecting "," or ";" in /var/www/html/index.php on line 15
Hãy đưa bước này vào quy trình làm việc — chạy trước mỗi lần test trên trình duyệt.
3. Bật hiển thị lỗi trong quá trình phát triển
Thấy trang trắng trống? PHP đang ẩn lỗi đi. Thêm ba dòng này vào đầu script của bạn tạm thời:
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
Muốn sửa trong php.ini thay thế:
display_errors = On
error_reporting = E_ALL
Sau khi chỉnh php.ini, khởi động lại server:
sudo systemctl restart php8.2-fpm
# hoặc
sudo systemctl restart apache2
Nguyên Nhân Thường Gặp Và Cách Sửa
Thiếu dấu chấm phẩy
Nguyên nhân của phần lớn các lỗi này. Mọi câu lệnh PHP đều kết thúc bằng ; — không có ngoại lệ.
// Sai
$name = "Alice"
echo $name;
// Đúng
$name = "Alice";
echo $name;
Dấu nháy không khớp hoặc chưa đóng
Mở một dấu nháy rồi quên đóng, PHP sẽ tiếp tục đọc cho đến khi tìm thấy dấu nháy khớp — nuốt mọi thứ ở giữa, kể cả dòng mới.
// Sai — mở dấu nháy đơn, không bao giờ đóng
$sql = 'SELECT * FROM users WHERE id = 1;
echo $sql;
// Đúng
$sql = 'SELECT * FROM users WHERE id = 1';
echo $sql;
Dấu ngoặc đơn hoặc dấu ngoặc nhọn chưa đóng
// Sai — thiếu dấu ngoặc đơn đóng
if ($x > 0 {
echo "positive";
}
// Đúng
if ($x > 0) {
echo "positive";
}
Lỗi cú pháp Heredoc
Heredoc có quy tắc định dạng nghiêm ngặt. Trên PHP cũ hơn 7.3, định danh đóng phải nằm ở cột 0 — không có khoảng trắng phía trước, không có khoảng trắng phía sau, chỉ là nhãn và dấu chấm phẩy.
// Sai trên PHP < 7.3 — thẻ đóng bị thụt vào
$text = <<<EOT
Some text
EOT;
// Đúng cho mọi phiên bản PHP — thẻ đóng ở cột 0
$text = <<<EOT
Some text
EOT;
// PHP 7.3+ cũng chấp nhận thụt vào đồng nhất ở thẻ đóng
$text = <<<EOT
Some text
EOT;
Cú pháp PHP 8 trên server PHP 7
Named arguments, biểu thức match, và toán tử nullsafe (?->) đều yêu cầu PHP 8.0+. Chạy đoạn code đó trên PHP 7 sẽ gây ra parse error ngay lập tức.
# Kiểm tra phiên bản đang thực sự chạy
php --version
# Named arguments — chỉ PHP 8.0+ trở lên
array_slice(array: $arr, offset: 0, length: 3); // Lỗi trên PHP 7.x
Hãy nâng cấp lên PHP 8 hoặc viết lại code bị ảnh hưởng để dùng positional arguments.
BOM hoặc ký tự vô hình
Các file được dán từ tài liệu Word hoặc lưu với encoding UTF-8 BOM thường mang theo các byte vô hình trước <?php. PHP nhìn thấy chúng, bị nhầm lẫn, và chết trước khi đến được code của bạn.
# Kiểm tra BOM
file /var/www/html/index.php
# Xóa bằng sed
sed -i '1s/^\xEF\xBB\xBF//' /var/www/html/index.php
Xác Nhận Đã Sửa Xong
Sau khi thực hiện thay đổi, hãy lint trước — rồi mới test trên trình duyệt. Đừng bỏ qua bước lint.
php -l /var/www/html/index.php
Sau đó chạy script trực tiếp hoặc truy cập qua HTTP:
php /var/www/html/index.php
# hoặc
curl -I http://localhost/index.php
Đang dùng Nginx + PHP-FPM? Cũng nên kiểm tra log lỗi của FPM — nó thường hiển thị các lỗi không xuất hiện trên trình duyệt:
sudo tail -f /var/log/php8.2-fpm.log
Bài Học Rút Ra
- Dòng được báo cáo hiếm khi là dòng bị lỗi. Nhìn lên một hoặc hai dòng phía trên nó. Biểu thức chưa đóng bắt đầu từ đó, không phải nơi PHP phàn nàn.
- Chạy
php -lthường xuyên. Tích hợp vào hành động lưu file trong editor hoặc pre-commit hook. Lỗi cú pháp không có lý do gì để đến được server. - Tắt display_errors trên môi trường production. Parse error làm lộ đường dẫn file và cấu trúc code nội bộ. Ghi log phía server; đừng bao giờ in ra cho người dùng thấy.
- Cài đặt linter thời gian thực. PHP Intelephense cho VS Code hoặc trình kiểm tra tích hợp của PhpStorm phát hiện lỗi cú pháp ngay khi bạn gõ — không cần chờ đến runtime mới biết mình quên dấu chấm phẩy.

