Cảnh báoBạn đang kiểm tra nhật ký lỗi (error logs) và thấy một loạt các cảnh báo. Dòng 42 đang thông báo: Warning: Invalid argument supplied for foreach(). Đây là một vấn đề kinh điển trong PHP. Thông thường, nó có nghĩa là bạn đang cố gắng lặp qua một biến không phải là một tập hợp (collection).
Tại sao lỗi này xảy raCấu trúc foreach khá "kén chọn". Nó yêu cầu bắt buộc phải là một array (mảng) hoặc một object (đối tượng) có thực thi interface Traversable. Nếu bạn truyền vào null, một string (chuỗi), hoặc một boolean, PHP sẽ dừng lại và đưa ra cảnh báo này. Điều này thường xảy ra khi một hàm mà bạn mong đợi trả về dữ liệu lại bị lỗi và trả về false thay vì mảng.
Các kịch bản thực tế- Truy vấn cơ sở dữ liệu trống: Một lời gọi PDO::fetch() trả về false vì không có hàng nào khớp với tiêu chí của bạn.- Phản hồi API bị lỗi: json_decode() trả về null vì một dịch vụ bên ngoài đã gửi trang HTML 404 thay vì mã JSON hợp lệ.- Logic bị bỏ qua: Một biến chỉ được khởi tạo bên trong câu lệnh if nhưng câu lệnh đó không bao giờ được thực thi.- Biến chưa được khởi tạo: Bạn đã tham chiếu đến một biến chưa từng được khai báo là một mảng.## Cách khắc phục lỗi### 1. Sử dụng toán tử Null Coalescing (Tốt nhất cho PHP 7+)Toán tử ?? là giải pháp sạch sẽ nhất cho mã nguồn hiện đại. Nó cho phép bạn cung cấp một mảng trống dự phòng ngay lập tức nếu biến bị thiếu hoặc mang giá trị null.
// Cách an toàn hơn:
foreach ($users ?? [] as $user) {
echo $user['name'];
}
2. Ép kiểu mảng nhanhNếu bạn muốn ép biến về định dạng có thể lặp lại (iterable), hãy ép kiểu nó. Việc này sẽ chuyển null thành một mảng trống và một chuỗi đơn lẻ thành một mảng chứa chuỗi đó.
// Đảm bảo đầu vào luôn có thể lặp lại
foreach ((array)$userData as $item) {
process($item);
}
Cảnh báo: Hãy cẩn thận với kiểu boolean. Ép kiểu false sẽ tạo ra [false], nghĩa là vòng lặp của bạn sẽ chạy một lần với một giá trị vô dụng.
3. Kiểm tra phòng thủ với is_iterable()Đối với các logic phức tạp, hãy sử dụng is_iterable() (có từ PHP 7.1). Nó mạnh mẽ hơn is_array() vì nó cũng tính đến các đối tượng có thể lặp lại.
if (is_iterable($products)) {
foreach ($products as $product) {
echo $product->title;
}
} else {
// Xử lý trạng thái "không có dữ liệu" một cách khéo léo
echo "Không có sản phẩm nào.";
}
4. Bắt đầu với một mảng trốngNgăn ngừa lỗi bằng cách khởi tạo các biến của bạn ở đầu tập lệnh. Điều này đảm bảo vòng lặp luôn có thứ gì đó để xem xét, ngay cả khi nó trống.
$results = []; // Khởi tạo sớm
if ($searchActive) {
$results = $db->getResults() ?: []; // Dự phòng mảng trống nếu là false
}
foreach ($results as $row) {
// Không có cảnh báo ở đây
}

