Toán tử (operator) nhận một hoặc nhiều giá trị và tạo ra một giá trị mới: $a + $b cộng, $a . $b nối chuỗi, $a && $b là phép AND logic, $a === $b so sánh, $i++ tăng thêm 1.
/ trả về số thực, trừ khi hai số nguyên chia hết cho nhau: 17 / 5 là 3.4, 10 / 5 là số nguyên 2. Khi chỉ cần phần nguyên, hãy dùng intdiv(). Cách làm tròn có ở trang toán học.
Toán tử số học
| Toán tử | Tên | Ví dụ | Kết quả |
|---|---|---|---|
+ | Cộng | 7 + 2 | 9 |
- | Trừ | 7 - 2 | 5 |
* | Nhân | 7 * 2 | 14 |
/ | Chia | 7 / 2 | 3.5 |
% | Chia lấy dư | 7 % 2 | 1 |
** | Lũy thừa | 7 ** 2 | 49 |
-$a | Đổi dấu | -7 | -7 |
Chia lấy dư rất hữu ích cho việc "cứ mỗi phần tử thứ N" và kiểm tra chẵn lẻ. Kết quả mang dấu của vế trái, và chia cho 0 sẽ ném ra một lỗi mà bạn có thể bắt:
Toán tử gán
= lưu một giá trị. Mỗi toán tử số học và toán tử chuỗi đều có dạng kết hợp để cập nhật trực tiếp một biến.
??= thuộc họ toán tử null coalescing. Nó chỉ gán khi biến chưa được đặt hoặc là null.
Tăng và giảm: ++ và --
$i++ trả về giá trị hiện tại rồi mới cộng 1. ++$i cộng 1 rồi trả về giá trị mới. Khác biệt chỉ lộ ra khi bạn dùng kết quả trong cùng một biểu thức.
Mẹo tăng chữ cái này thường được dùng để tạo tên cột kiểu bảng tính (A, B, ... Z, AA).
Toán tử logic: &&, ||, ! và xor
| Toán tử | Đúng khi |
|---|---|
$a && $b | cả hai đều đúng |
$a || $b | ít nhất một vế đúng |
!$a | $a sai |
$a xor $b | đúng một vế đúng |
$a and $b, $a or $b | giống && và ||, nhưng độ ưu tiên thấp hơn |
&& và || đánh giá ngắn mạch: vế phải không được tính khi vế trái đã quyết định kết quả. Nhờ vậy isset($user) && $user->isAdmin() mới an toàn.
and và &&: cái bẫy độ ưu tiên
and và or có độ ưu tiên thấp hơn =, nên trong một phép gán chúng chỉ được áp dụng sau khi giá trị đã được lưu. Đây là một bug kinh điển:
Độ ưu tiên thấp lại hữu ích trong một cách viết quen thuộc, $file = fopen($path, 'r') or die('Cannot open');, khi bạn muốn phép gán xảy ra trước. Ở mọi chỗ khác, hãy dùng && và ||.
Toán tử chuỗi: . và .=
PHP có hai toán tử chuỗi: . nối hai chuỗi ("Grace" . " " . "Hopper") và .= nối thêm vào một biến ($html .= "<li>"). + không bao giờ nối chuỗi: "3" + "4" là số 7, còn "3" . "4" là chuỗi "34". Trang chuỗi nói về nội suy biến và các loại dấu nháy.
So sánh và toán tử spaceship <=>
== so sánh sau khi chuyển kiểu, === kiểm tra cả kiểu, còn <=> trả về -1, 0 hoặc 1, đúng thứ mà các hàm callback sắp xếp cần. Chi tiết và bảng so sánh lỏng đầy đủ có ở trang toán tử so sánh.
Toán tử mảng
+ với mảng là phép hợp: khóa của mảng bên trái được ưu tiên và chỉ những khóa còn thiếu mới được thêm từ mảng bên phải. Điều này làm bất ngờ những ai tưởng nó nối thêm vào cuối. == kiểm tra các cặp khóa/giá trị giống nhau, === còn đòi hỏi cùng thứ tự và cùng kiểu.
Để nối một danh sách vào sau danh sách khác, dùng array_merge() hoặc cú pháp spread [...$a, ...$b].
Độ ưu tiên toán tử
Khi một biểu thức trộn nhiều toán tử, PHP áp dụng chúng theo một thứ tự cố định. Đây là những trường hợp hay khiến người ta vấp, kèm kết quả PHP 8.3 in ra:
echo 2 + 3 * 4; // 14: * before +
echo (2 + 3) * 4; // 20
echo 2 ** 3 ** 2; // 512: right to left, 2 ** 9
echo -2 ** 2; // -4: ** before unary minus
echo "Sum: " . 2 + 3; // Sum: 5, since PHP 8 + runs before .
Khi còn phân vân, hãy thêm dấu ngoặc. Chúng chẳng tốn gì, và người đọc dòng code sau bạn không phải nhớ bảng độ ưu tiên.
Câu hỏi thường gặp
and và && trong PHP khác nhau thế nào?
Cả hai đều là phép AND logic, nhưng and có độ ưu tiên thấp hơn =. Vì vậy $x = true and false; lưu true vào $x (phép gán xảy ra trước), còn $x = true && false; lưu false. Dùng && và || trong biểu thức và đừng dùng and/or trong phép gán.
% trong PHP làm gì?
% là toán tử chia lấy dư (modulo): nó trả về phần dư của phép chia số nguyên, nên 10 % 3 là 1. Kết quả mang dấu của toán hạng bên trái (-7 % 3 là -1). Với số thực, dùng fmod(), còn % 0 ném ra DivisionByZeroError.
Làm sao tính lũy thừa trong PHP?
Dùng toán tử **: 2 ** 10 là 1024. Toán tử này kết hợp từ phải sang trái, nên 2 ** 3 ** 2 là 2 ** 9 = 512, và nó gắn chặt hơn dấu trừ một ngôi, nên -2 ** 2 là -4. Hàm pow(2, 10) cũng làm được như vậy.
$i++ và ++$i trong PHP khác nhau thế nào?
Cả hai đều cộng 1 vào $i. $i++ (tăng sau) trả về giá trị cũ rồi mới tăng; ++$i (tăng trước) tăng trước rồi trả về giá trị mới. Khi đứng riêng trên một dòng, như bước của vòng lặp for, chúng không khác gì nhau.