Xử lý lỗi trong PHP
“Good error handling isn’t about preventing bugs — it’s about designing failure paths as carefully as success paths.”
Xử lý lỗi (error handling) là một trong những phần quan trọng nhưng thường bị xem nhẹ trong lập trình. Điều này không chỉ đúng với PHP, mà với mọi ngôn ngữ và mọi hệ thống phần mềm.
Trong khi chúng ta dành nhiều thời gian để thiết kế các luồng xử lý “happy path” — nơi mọi thứ diễn ra đúng như kỳ vọng — thì các luồng thất bại lại thường bị làm qua loa, hoặc tệ hơn là… bị bỏ quên hoàn toàn.
Thực tế, phần lớn bug nghiêm trọng trong production không đến từ logic chính, mà đến từ những tình huống lỗi không được xử lý đúng cách.
Vì Sao Error Handling Lại Quan Trọng?
Hãy lấy một ví dụ quen thuộc: chuyển tiền từ tài khoản A sang tài khoản B.
Ngoài logic chuyển tiền thông thường, hệ thống luôn phải đối mặt với hàng loạt tình huống lỗi tiềm ẩn:
-
Số dư tài khoản A không đủ
-
Lỗi kết nối database
-
Lỗi mạng trong quá trình xử lý
-
Lỗi phần cứng hoặc timeout
-
Một service bên thứ ba (ví dụ: gửi email, webhook) bị lỗi
Nếu các trường hợp này không được xử lý rõ ràng, hậu quả có thể rất nghiêm trọng:
-
Dữ liệu không toàn vẹn
-
Trạng thái hệ thống không nhất quán
-
Luồng xử lý khó đoán, khó debug
-
Lỗi dây chuyền lan sang các chức năng khác
Trong quá trình review nhiều codebase khác nhau, chúng ta có thể dễ dàng nhận thấy 4 lỗi xử lý exception rất phổ biến, đặc biệt trong các dự án PHP / Laravel.
1. Blind catch

Sử dụng class Exception cho toàn bộ các lỗi.
Hậu quả:
- Tất cả các lỗi đều chỉ được xử lý theo một cách duy nhất, gây khó hiểu cho người dùng.
Giải pháp:

2. Empty catch

Hậu quả:
- Trong trường hợp cậu lệnh bị lỗi, dữ liệu sẽ được xử lý không toàn vẹn. Với ví dụ trên, giả sử database bị lỗi khiến user không được lưu, nhưng bên dưới có thể có những đoạn code lấy user từ database để xử lý, mà user không tồn tại hoặc đang ở trạng thái cũ, nên sẽ làm cho luồng xử lý không còn chính xác nữa, hoặc gây ra lỗi nghiêm trọng hơn.
- Việc các lỗi bị ẩn đi có thể khiến cho chương trình hoạt động theo một cách khó dự đoán, hoặc gây ra các lỗi không kiểm soát được, đồng thời sẽ khiện cho việc debug gặp khó khăn.
Giải pháp:

3. Transaction siêu nhân

Hậu quả:
- Table có thể bị lock hoặc bị out-of-memory nếu logic bên trong transaction được thực thi quá lâu.
- Transaction có thể bị rollBack bởi lỗi không liên quan như send email.
Giải pháp:

4. Bị lặp try/catch trong controller

Hậu quả:
- Bị lặp try/catch trong tất cả các action của controller.
Giải pháp:

Những việc cần làm ngay, đặc biệt đối với codebase Laravel.
- Tìm kiếm toàn bộ catch(Exception) hoặc catch (\Exception) và thay thế bằng các Exception cụ thể hơn.
- Tìm những empty catch ⇒ Xử lý chúng.
- Đảm bảo DB transactions chỉ nhóm lại những logic thuộc về database.
- Chuyển try/catch trong Controller vào app/Exceptions/Handler.php.

WRITE A COMMENT