Sử dụng toán tử ternary và null coalescing trong điều kiện PHP

PHP Tutorial | by Học PHP

Trong lập trình PHP, chúng ta thường xuyên cần kiểm tra điều kiện để quyết định giá trị của một biến hoặc hành động tiếp theo. Các câu lệnh if...else là công cụ mạnh mẽ và linh hoạt cho mục đích này. Tuy nhiên, đôi khi, những cấu trúc này có thể trở nên khá dài dòng, đặc biệt khi bạn chỉ cần gán một giá trị đơn giản dựa trên một điều kiện đúng hoặc sai.

Bạn có bao giờ ước có một cách ngắn gọn hơn, "một dòng" để thể hiện logic "nếu điều này đúng thì là A, còn không thì là B" không? Hoặc một cách an toàn để lấy giá trị từ một biến mà bạn không chắc chắn liệu nó đã tồn tại hay chưa, mà không gây ra lỗi?

May mắn thay, PHP cung cấp hai toán tử cực kỳ hữu ích để giải quyết những vấn đề này: Toán tử Ternary (? :)Toán tử Null Coalescing (??). Chúng cho phép bạn viết mã súc tích, dễ đọc hơn cho các trường hợp điều kiện phổ biến. Hãy cùng mình cách hai toán tử này giúp bạn tối ưu hóa code PHP của mình nhé!

Cách rút gọn điều kiện if...else trong PHP

Trong lập trình PHP, câu lệnh if...else là một công cụ cơ bản và cực kỳ mạnh mẽ. Nó cho phép chương trình của bạn đưa ra quyết định, thực hiện hành động A nếu một điều kiện đúng, và hành động B nếu điều kiện đó sai. Chẳng hạn, bạn có thể dùng if...else để kiểm tra xem một học sinh đỗ hay trượt, hay để hiển thị lời chào "Chào buổi sáng" hoặc "Chào buổi chiều" tùy theo thời gian trong ngày.

Ví dụ về if...else:

<?php
$diem = 75;
$ketQua = "";

if ($diem >= 50) {
    $ketQua = "Đỗ";
} else {
    $ketQua = "Trượt";
}
echo "Kết quả học tập: " . $ketQua; // Output: Kết quả học tập: Đỗ
?>

if...else rất rõ ràng và dễ hiểu, đặc biệt khi logic của bạn phức tạp. Tuy nhiên, bạn có thấy rằng, đôi khi, để gán một giá trị đơn giản dựa trên một điều kiện, chúng ta phải viết tới 5 hoặc 6 dòng code không? Điều này có thể hơi dài dòng và chiếm nhiều không gian trong mã nguồn, nhất là khi chúng ta có rất nhiều điều kiện tương tự.

Vấn đề đặt ra là: Làm thế nào để chúng ta có thể viết những điều kiện đơn giản như thế này một cách ngắn gọnsúc tích hơn, đặc biệt khi chỉ có đúng hai lựa chọn hành động?

Đây chính là lúc PHP cung cấp cho chúng ta hai giải pháp tuyệt vời: Toán tử Ternary (? :)Toán tử Null Coalescing (??). Cả hai đều là những công cụ mạnh mẽ giúp bạn rút gọn đáng kể số lượng dòng code, làm cho mã nguồn trở nên gọn gàng và dễ đọc hơn cho các trường hợp cụ thể. Chúng ta sẽ tìm hiểu chi tiết về từng toán tử để thấy cách chúng hoạt động và khi nào nên sử dụng chúng.

Toán tử Ternary (Toán tử ba ngôi) trong PHP

Toán tử Ternary, hay còn gọi là toán tử ba ngôi, được tạo ra để giúp bạn viết gọn một câu lệnh if...else đơn giản thành chỉ một dòng duy nhất. Nó hoạt động giống như một "câu hỏi nhanh" với hai câu trả lời có thể xảy ra. Nếu điều kiện đúng, nó trả về kết quả này; nếu sai, nó trả về kết quả kia.

Cú pháp

Cú pháp của toán tử Ternary rất dễ nhớ và có ba phần (vì vậy mới gọi là "ba ngôi"):

điều_kiện ? giá_trị_nếu_đúng : giá_trị_nếu_sai;
  • điều_kiện: Đây là biểu thức được kiểm tra. Kết quả của nó phải là true hoặc false.
  • ?: Dấu hỏi, tượng trưng cho "thì".
  • giá_trị_nếu_đúng: Giá trị hoặc biểu thức được trả về nếu điều_kiệntrue.
  • :: Dấu hai chấm, tượng trưng cho "còn không thì".
  • giá_trị_nếu_sai: Giá trị hoặc biểu thức được trả về nếu điều_kiệnfalse.

Cách hoạt động

Cách hoạt động của toán tử này cực kỳ trực quan:

  • PHP sẽ kiểm tra điều_kiện ở vế trái của dấu hỏi.
  • Nếu điều_kiệntrue, toàn bộ biểu thức Ternary sẽ trả về giá_trị_nếu_đúng (vế nằm giữa ?:).
  • Nếu điều_kiệnfalse, toàn bộ biểu thức sẽ trả về giá_trị_nếu_sai (vế nằm sau :).

Ví dụ cơ bản

Hãy xem cách chúng ta có thể rút gọn các câu lệnh if...else thông thường bằng toán tử Ternary.

Gán trạng thái "Đỗ" hoặc "Trượt" dựa trên điểm:

  • Cách dùng if...else thông thường:

<?php
$diem = 75;
$ketQua = "";

if ($diem >= 50) {
    $ketQua = "Đỗ";
} else {
    $ketQua = "Trượt";
}

echo "Kết quả: " . $ketQua; // Output: Kết quả: Đỗ
?>

Cách dùng Toán tử Ternary:

<?php
$diem = 75;
// Kiểm tra: $diem có >= 50 không? (Đúng)
// Nếu đúng, gán "Đỗ", nếu sai gán "Trượt"
$ketQua = ($diem >= 50) ? "Đỗ" : "Trượt";

echo "Kết quả: " . $ketQua; // Output: Kết quả: Đỗ
?>

Bạn thấy đó, 5 dòng code đã được rút gọn thành một dòng duy nhất, cực kỳ gọn gàng.

Gán thông báo "Đã đăng nhập" hoặc "Chưa đăng nhập":

  • Cách dùng if...else thông thường:

<?php
$daDangNhap = true;
$thongBao = "";

if ($daDangNhap == true) {
    $thongBao = "Chào mừng bạn đã đăng nhập!";
} else {
    $thongBao = "Vui lòng đăng nhập để tiếp tục.";
}

echo $thongBao; // Output: Chào mừng bạn đã đăng nhập!
?>

Cách dùng Toán tử Ternary:

<?php
$daDangNhap = true;
// Kiểm tra: $daDangNhap có bằng true không? (Đúng)
// Nếu đúng, gán thông báo "Đã đăng nhập", nếu sai gán "Chưa đăng nhập"
$thongBao = $daDangNhap ? "Chào mừng bạn đã đăng nhập!" : "Vui lòng đăng nhập để tiếp tục.";

echo $thongBao; // Output: Chào mừng bạn đã đăng nhập!
?>

Lợi ích và hạn chế

Lợi ích:

  • Code ngắn gọn: Rút gọn nhiều dòng thành một dòng duy nhất.
  • Dễ đọc: Với những điều kiện đơn giản, cú pháp này rất trực quan và dễ hiểu.
  • Hiệu quả: Giúp tăng tốc độ viết code và giảm thiểu sự cồng kềnh.

Hạn chế:

  • Không nên lạm dụng: Khi điều_kiện trở nên quá phức tạp (ví dụ: có nhiều toán tử && hay || lồng nhau), hoặc khi giá_trị_nếu_đúng/sai là những biểu thức dài, việc sử dụng Ternary có thể khiến code khó đọc và khó hiểu hơn cả if...else thông thường.
  • Không dùng cho nhiều lựa chọn: Toán tử này chỉ phù hợp với hai lựa chọn. Nếu bạn có nhiều hơn hai, hãy dùng if...elseif...else.

Trong trường hợp cần gán giá trị mặc định cho một biến có thể không tồn tại, toán tử Ternary vẫn hoạt động, nhưng PHP có một toán tử chuyên dụng và an toàn hơn cho mục đích đó.

Toán tử Null Coalescing (Toán tử kết hợp rỗng) trong PHP

Toán tử Null Coalescing (??) là một bổ sung tuyệt vời từ PHP 7. Nó ra đời với mục đích cụ thể là cung cấp một giá trị mặc định cho một biến hoặc một biểu thức nếu biến/biểu thức đó không tồn tại hoặc có giá trị là null. Đây là một công cụ cực kỳ hữu ích khi bạn làm việc với dữ liệu mà không chắc chắn liệu nó có được cung cấp hay không, ví dụ như dữ liệu từ form ($_POST, $_GET), cấu hình từ cơ sở dữ liệu, hoặc các tham số tùy chọn.

Vấn đề nó giải quyết

Trước khi có toán tử ??, để kiểm tra xem một biến có tồn tại và khác null hay không, bạn thường phải dùng hàm isset() hoặc empty() kết hợp với toán tử ternary (? :). Nếu không kiểm tra cẩn thận, bạn rất dễ gặp phải các lỗi khó chịu như "Undefined index" (khi truy cập một phần tử không tồn tại trong mảng) hoặc "Undefined variable" (khi truy cập một biến chưa được khai báo).

Ví dụ về cách làm truyền thống (trước PHP 7):

<?php
// Giả sử URL là: your_site.com/index.php (không có ?name=)

// Cách truyền thống với isset() và toán tử ternary
$userName = isset($_GET['name']) ? $_GET['name'] : "Khách";
echo "Chào: " . $userName; // Output: Chào: Khách (không lỗi)

// Nếu không kiểm tra isset(), sẽ gây lỗi nếu $_GET['name'] không tồn tại
// $userName = $_GET['name']; // Dòng này sẽ báo lỗi "Undefined index: name"
?>

Toán tử ?? giúp bạn loại bỏ sự phức tạp này, làm cho code gọn gàng và an toàn hơn nhiều.

Cú pháp

Cú pháp của toán tử Null Coalescing rất đơn giản:

biến_hoặc_biểu_thức_có_thể_null ?? giá_trị_mặc_định;
  • biến_hoặc_biểu_thức_có_thể_null: Đây là vế mà bạn muốn kiểm tra. Có thể là một biến, một phần tử của mảng, hoặc kết quả của một hàm.
  • ??: Toán tử Null Coalescing.
  • giá_trị_mặc_định: Giá trị sẽ được sử dụng nếu vế bên trái không tồn tại hoặc là null.

Cách hoạt động

Cách hoạt động của ?? rất rõ ràng và hiệu quả:

  • PHP sẽ kiểm tra vế bên trái (biến_hoặc_biểu_thức_có_thể_null).
  • Nếu vế trái tồn tại (đã được khai báo) có giá trị KHÁC null, thì toàn bộ biểu thức sẽ trả về giá trị của vế trái.
  • Nếu vế trái không tồn tại (chưa được khai báo) HOẶC có giá trị là null, thì toàn bộ biểu thức sẽ trả về giá_trị_mặc_định ở vế bên phải.

Ví dụ cơ bản

Hãy xem cách ?? giúp đơn giản hóa code trong các tình huống phổ biến:

Lấy tên người dùng từ URL ($_GET['name']) hoặc dùng tên "Khách":

  • Giả sử URL không có tham số name (ví dụ: https://localhost/index.php)

<?php
// $_GET['name'] không tồn tại và sẽ không gây lỗi
$userName = $_GET['name'] ?? "Khách";
echo "Chào: " . $userName; // Output: Chào: Khách
?>

Giả sử URL có tham số name (ví dụ: https://localhost/index.php?name=An)

<?php
$_GET['name'] = "An"; // Giả lập dữ liệu từ URL
$userName = $_GET['name'] ?? "Khách";
echo "Chào: " . $userName; // Output: Chào: An
?>

Giả sử URL có tham số name nhưng giá trị là null (ít gặp trực tiếp từ URL, nhưng có thể xảy ra với biến):

<?php
$_GET['name'] = null; // Giả lập dữ liệu từ URL hoặc từ một biến nào đó
$userName = $_GET['name'] ?? "Khách";
echo "Chào: " . $userName; // Output: Chào: Khách
?>

Lấy số trang từ dữ liệu ($data['page']) hoặc mặc định là 1:

  • Giả sử $data là một mảng và không có key 'page':

<?php
$data = [
    'item_id' => 123,
    'title' => 'Sản phẩm X'
];

// $data['page'] không tồn tại, nên sẽ lấy giá trị mặc định là 1
$pageNumber = $data['page'] ?? 1;
echo "Bạn đang ở trang: " . $pageNumber; // Output: Bạn đang ở trang: 1
?>

Giả sử $data có key 'page' với giá trị hợp lệ:

<?php
$data = [
    'item_id' => 123,
    'title' => 'Sản phẩm Y',
    'page' => 5
];

// $data['page'] tồn tại và khác null, nên sẽ lấy giá trị 5
$pageNumber = $data['page'] ?? 1;
echo "Bạn đang ở trang: " . $pageNumber; // Output: Bạn đang ở trang: 5
?>

Lợi ích và Hạn chế

Lợi ích:

  • Cực kỳ ngắn gọn: Giảm đáng kể số lượng code so với việc dùng isset() hoặc empty() với toán tử ternary.
  • An toàn hơn: Tránh hoàn toàn lỗi "Undefined index" hoặc "Undefined variable" khi truy cập các biến có thể không tồn tại.
  • Dễ đọc: Mã nguồn trở nên rõ ràng hơn, dễ hiểu mục đích của việc gán giá trị mặc định.
  • Có thể nối chuỗi: Bạn có thể dùng nhiều toán tử ?? liên tiếp để kiểm tra nhiều biến/giá trị theo thứ tự ưu tiên: $var1 ?? $var2 ?? $defaultValue;

Hạn chế:

Chỉ kiểm tra null hoặc không tồn tại: Toán tử ?? KHÔNG kiểm tra các giá trị được coi là "rỗng" khác như:

  • Chuỗi rỗng ("")
  • Số 0
  • Mảng rỗng ([])
  • Boolean false
  • Nếu bạn cần kiểm tra những giá trị này là "rỗng" để gán mặc định, bạn vẫn cần sử dụng hàm empty() (thường là kết hợp với toán tử ternary).

Ví dụ về hạn chế:

<?php
$usernameInput = ""; // Người dùng gửi chuỗi rỗng từ form

// Dùng ?? sẽ KHÔNG hoạt động như mong muốn nếu bạn muốn "Anonymous" khi chuỗi rỗng
$displayName = $usernameInput ?? "Anonymous";
echo "Hi: " . $displayName; // Output: Hi: (chuỗi rỗng), không phải "Anonymous"

echo "<br>";

// Để xử lý giá trị rỗng (empty), bạn vẫn cần dùng empty() (thường kết hợp với ternary)
$displayNameWithEmptyCheck = empty($usernameInput) ? "Anonymous" : $usernameInput;
echo "Hi (with empty check): " . $displayNameWithEmptyCheck; // Output: Hi (with empty check): Anonymous
?>

So sánh và khi nào sử dụng Toán tử Ternary (? :) và Null Coalescing (??)?

Sau khi đã tìm hiểu chi tiết về từng toán tử, điều quan trọng là phải biết khi nào nên sử dụng cái nào để mã của bạn không chỉ ngắn gọn mà còn rõ ràng và chính xác. Mặc dù cả hai đều giúp rút gọn code, nhưng chúng giải quyết các vấn đề hơi khác nhau.

Toán tử Ternary (? :)

Khi nào sử dụng?

  • Bạn nên dùng toán tử Ternary khi bạn có một điều kiện rõ ràng và cần chọn giữa hai giá trị hoặc hành động cụ thể dựa trên việc điều kiện đó là true hay false.
  • Nó lý tưởng cho việc gán giá trị vào một biến, hoặc in ra một chuỗi ngay lập tức, tùy thuộc vào kết quả của một phép kiểm tra.
  • Cả hai vế (giá_trị_nếu_đúnggiá_trị_nếu_sai) đều phải được định nghĩa rõ ràng.

Ví dụ minh họa:

<?php
// Ví dụ 1: Gán trạng thái nút dựa trên biến boolean
$isUserLoggedIn = true;
$buttonText = $isUserLoggedIn ? "Đăng xuất" : "Đăng nhập";
echo "Nút hiện tại: " . $buttonText . "<br>"; // Output: Nút hiện tại: Đăng xuất

$isUserLoggedIn = false;
$buttonText = $isUserLoggedIn ? "Đăng xuất" : "Đăng nhập";
echo "Nút hiện tại: " . $buttonText . "<br>"; // Output: Nút hiện tại: Đăng nhập

echo "<br>";

// Ví dụ 2: Hiển thị thông báo dựa trên số lượng sản phẩm
$productCount = 0;
$message = ($productCount > 0) ? "Có " . $productCount . " sản phẩm trong giỏ hàng." : "Giỏ hàng của bạn đang trống.";
echo $message . "<br>"; // Output: Giỏ hàng của bạn đang trống.

$productCount = 3;
$message = ($productCount > 0) ? "Có " . $productCount . " sản phẩm trong giỏ hàng." : "Giỏ hàng của bạn đang trống.";
echo $message; // Output: Có 3 sản phẩm trong giỏ hàng.
?>

Toán tử Null Coalescing (??)

Khi nào sử dụng?

  • Bạn nên dùng toán tử Null Coalescing khi bạn muốn cung cấp một giá trị mặc định cho một biến hoặc biểu thức mà bạn không chắc chắn liệu nó có tồn tại (đã được khai báo) hay có giá trị là null hay không.
  • Nó đặc biệt hữu ích khi làm việc với dữ liệu có thể thiếu, như tham số URL ($_GET), dữ liệu form ($_POST), hoặc các phần tử mảng không bắt buộc.
  • Mục tiêu chính là tránh lỗi "Undefined variable" hoặc "Undefined index".

Ví dụ minh họa:

<?php
// Ví dụ 1: Lấy tên người dùng từ tham số URL hoặc dùng mặc định
// Giả sử không có ?user= trong URL (biến $_GET['user'] không tồn tại)
$username = $_GET['user'] ?? "Khách hàng";
echo "Chào mừng: " . $username . "<br>"; // Output: Chào mừng: Khách hàng

// Giả sử có ?user=Alice trong URL (biến $_GET['user'] tồn tại và có giá trị)
$_GET['user'] = "Alice"; // Giả lập biến $_GET
$username = $_GET['user'] ?? "Khách hàng";
echo "Chào mừng: " . $username . "<br>"; // Output: Chào mừng: Alice

// Giả sử có ?user= trong URL nhưng giá trị là null (có thể do gán null từ code khác)
$_GET['user'] = null;
$username = $_GET['user'] ?? "Khách hàng";
echo "Chào mừng: " . $username . "<br>"; // Output: Chào mừng: Khách hàng

echo "<br>";

// Ví dụ 2: Lấy cấu hình từ một mảng
$config = [
    'database_host' => 'localhost',
    'database_user' => 'root'
    // 'database_password' không tồn tại
];

$dbPassword = $config['database_password'] ?? 'password_default';
echo "Mật khẩu CSDL: " . $dbPassword . "<br>"; // Output: Mật khẩu CSDL: password_default

$dbHost = $config['database_host'] ?? '127.0.0.1';
echo "Host CSDL: " . $dbHost . "<br>"; // Output: Host CSDL: localhost
?>

Kết bài

Như vậy, chúng ta đã cùng nhau tìm hiểu về hai toán tử mạnh mẽ giúp tối ưu hóa code PHP: Toán tử Ternary (? :)Toán tử Null Coalescing (??).

  • Toán tử Ternary là lựa chọn tuyệt vời khi bạn cần rút gọn một câu lệnh if...else đơn giản thành một dòng duy nhất, phù hợp cho việc gán giá trị hoặc hiển thị thông báo dựa trên một điều kiện rõ ràng.
  • Toán tử Null Coalescing lại chuyên biệt hơn, cung cấp một cách cực kỳ an toàn và ngắn gọn để gán giá trị mặc định cho các biến hoặc biểu thức có thể không tồn tại hoặc mang giá trị null, đặc biệt hữu ích khi làm việc với dữ liệu không đảm bảo.

Việc hiểu rõ mục đích và cách thức hoạt động của từng toán tử sẽ giúp bạn viết code PHP không chỉ ngắn gọn hơn mà còn dễ đọc, dễ bảo trì và an toàn hơn, tránh được các lỗi không mong muốn. Hãy luyện tập và áp dụng chúng vào các dự án của mình để thấy rõ hiệu quả mà chúng mang lại!

Bài viết liên quan