Menu

Toán tử ba ngôi trong PHP: dạng rút gọn ?: và lồng nhau

Toán tử ba ngôi (ternary) trong PHP là một câu if/else trên một dòng: $result = $condition ? 'yes' : 'no';. Tìm hiểu dạng rút gọn ?: (toán tử Elvis), điểm khác với ??, vì sao toán tử ba ngôi lồng nhau cần dấu ngoặc từ PHP 8, và khi nào match là lựa chọn gọn hơn.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Toán tử ba ngôi (ternary operator) là một câu if/else gói gọn trong một biểu thức: condition ? valueIfTrue : valueIfFalse. Nó trả về một trong hai giá trị, nên bạn có thể gán nó cho biến, echo nó hoặc truyền nó vào một hàm.

Đổi $age thành 15 và $items thành 3 rồi chạy lại. Để ý cặp ngoặc quanh toán tử ba ngôi ở dòng cuối: thiếu chúng, dấu . sẽ nối các chuỗi trước và kết quả sẽ không như bạn muốn.

Toán tử ba ngôi trong template HTML

Toán tử ba ngôi là cách thường dùng để chọn class CSS, nhãn hoặc thuộc tính bên trong template. Khối này đọc ?stock= từ URL: hãy chạy nó, rồi bấm vào các liên kết trong tab Trang, cùng script đó sẽ chạy lại với một giá trị khác.

<?= ... ?> là dạng viết tắt của <?php echo ... ?>, giúp các điều kiện một dòng bên trong markup vẫn dễ đọc.

Toán tử ba ngôi rút gọn ?: (toán tử Elvis)

Bỏ phần ở giữa đi, bạn có $a ?: $b: nó trả về $a khi $a được coi là đúng, ngược lại trả về $b. Cách này tiện cho giá trị mặc định khi chuỗi rỗng hoặc 0 cũng cần thay bằng giá trị dự phòng.

Các giá trị được coi là sai (falsy) gồm false, 0, 0.0, "", "0", [] và null. Nếu "0" là một câu trả lời thật trong dữ liệu của bạn (ô số lượng, mã PIN), toán tử ba ngôi rút gọn sẽ vứt nó đi.

?: và ??

Hai toán tử trông giống nhau nhưng kiểm tra những thứ khác nhau. ?: dùng giá trị dự phòng khi vế trái được coi là sai. ?? chỉ dùng giá trị dự phòng khi vế trái là null hoặc chưa được đặt, và không cảnh báo khi thiếu biến hay khóa của mảng.

Dùng ?? khi "giá trị có thể không tồn tại" (dữ liệu request, mảng cấu hình, khóa tùy chọn). Dùng ?: khi "giá trị có tồn tại nhưng có thể rỗng". Trang toán tử null coalescing trình bày chi tiết ?? và ??=.

Toán tử ba ngôi lồng nhau cần dấu ngoặc

PHP 7 đọc a ? b : c ? d : e từ trái sang phải, khác với gần như mọi ngôn ngữ khác, và cho ra kết quả sai. PHP 8 từ chối đoán:

<?php
echo $score > 90 ? "A" : $score > 80 ? "B" : "C";
PHP Fatal error:  Unparenthesized `a ? b : c ? d : e` is not supported. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)` in /home/index.php on line 2

Thêm dấu ngoặc quanh toán tử ba ngôi bên trong là chạy được:

Toán tử ba ngôi rút gọn là ngoại lệ: $a ?: $b ?: $c được phép viết không cần dấu ngoặc, như trong ví dụ Elvis ở trên.

Dùng match(true) khi có hơn hai nhánh

Toán tử ba ngôi lồng ba hay bốn tầng rất khó đọc, kể cả khi có dấu ngoặc. match với true làm đối tượng so sánh sẽ kiểm tra các điều kiện từ trên xuống dưới và trả về nhánh khớp đầu tiên:

Giữ toán tử ba ngôi cho hai kết quả trên một dòng, và chuyển sang match hoặc chuỗi if/elseif ngay khi bạn cần đến kết quả thứ ba.

Câu hỏi thường gặp

Toán tử ba ngôi trong PHP là gì?

Một dạng rút gọn của if/else có trả về giá trị: $label = $age >= 18 ? 'adult' : 'minor';. Nếu điều kiện trước ? đúng, biểu thức sau ? được dùng, ngược lại là biểu thức sau :.

?: trong PHP nghĩa là gì?

$a ?: $b là toán tử ba ngôi rút gọn (còn gọi là toán tử Elvis). Nó trả về $a nếu $a được coi là đúng (truthy), ngược lại trả về $b, nên '' ?: 'default' là 'default'. Cách này giống $a ? $a : $b, nhưng $a chỉ được tính một lần.

Có thể lồng toán tử ba ngôi trong PHP không?

Chỉ khi có dấu ngoặc. Từ PHP 8, $a ? 'x' : $b ? 'y' : 'z' là lỗi nghiêm trọng (fatal error), nên hãy viết $a ? 'x' : ($b ? 'y' : 'z'). Khi có hơn hai nhánh, match(true) hoặc chuỗi if/elseif dễ đọc hơn.

Có thể dùng toán tử ba ngôi mà không có phần else không?

Không, toán tử ba ngôi luôn cần cả hai nhánh. Để "dùng giá trị này hoặc giá trị dự phòng", hãy viết $x ?: 'default' hoặc $x ?? 'default'; để chỉ làm gì đó khi điều kiện đúng, hãy viết câu lệnh if bình thường hoặc $condition && doSomething();.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu