PHP có tám kiểu dữ liệu (data type) bạn dùng hằng ngày: int, float, string, bool, array, object, null, cộng thêm callable cho các hàm được truyền qua lại. Biến không có kiểu cố định; giá trị hiện tại của biến mới có kiểu. var_dump($x) cho thấy cả kiểu lẫn giá trị, còn gettype($x) trả về kiểu dưới dạng chuỗi.
Cột đầu tiên là gettype(), cột thứ hai là get_debug_type(). Thay một giá trị bằng giá trị của bạn rồi chạy lại. Hai hàm gọi tên khác nhau ở vài chỗ: gettype nói integer, double và boolean vì lý do lịch sử, còn get_debug_type dùng tên trong khai báo kiểu (int, float, bool) và trả về tên lớp với đối tượng.
Tổng quan các kiểu dữ liệu PHP
| Kiểu | Ví dụ | Ghi chú |
|---|---|---|
int | 42, -7, 0x1A, 1_000_000 | số nguyên, 64-bit trên các hệ thống hiện đại |
float | 3.14, 1.5e3 | số thập phân, không chính xác tuyệt đối như ở mọi ngôn ngữ |
string | "hi", 'hi' | một dãy byte, không phải dãy ký tự |
bool | true, false | không phân biệt hoa thường (TRUE cũng được) |
array | [1, 2], ["a" => 1] | ánh xạ có thứ tự: vừa là danh sách vừa là từ điển |
object | new User(), new stdClass() | một instance của một lớp |
null | null | giá trị duy nhất của kiểu null; cũng có nghĩa "chưa có giá trị" |
callable | 'strlen', fn($x) => $x * 2 | bất cứ thứ gì gọi được |
iterable | một mảng hoặc một đối tượng Traversable | thứ mà foreach chấp nhận |
resource | kết quả của fopen() | một handle trỏ tới thứ gì đó bên ngoài PHP |
Xem giá trị bằng var_dump
var_dump là công cụ để thấy thứ bạn thật sự đang có. Nó in ra kiểu, giá trị, và với chuỗi thì cả độ dài tính bằng byte:
echo sẽ in ra 10 cho ba giá trị đầu và che mất sự khác biệt. Độ dài trong string(5) "café" đếm theo byte, đó là lý do strlen và mb_strlen cho kết quả khác nhau với văn bản ngoài ASCII.
Số nguyên và số thực
Số nguyên (integer) là số không có phần thập phân. Khi viết giá trị trực tiếp, bạn có thể dùng dấu gạch dưới cho dễ đọc, và dùng cách viết thập lục phân, bát phân, nhị phân. Số thực (float) là bất kỳ số nào có dấu chấm thập phân hoặc số mũ, và như ở mọi ngôn ngữ, phần lớn số thập phân chỉ được lưu gần đúng:
Đừng bao giờ so sánh số thực bằng ==; hãy so sánh hiệu của chúng với một sai số nhỏ, hoặc làm tròn cả hai vế trước. Với tiền, hãy lưu số xu (cent) dưới dạng số nguyên.
Boolean và những giá trị được coi là false
Một bool là true hoặc false. Ở nơi PHP cần một điều kiện (if, while, !), mọi giá trị đều được chuyển sang bool, và chỉ một danh sách ngắn được coi là false: false, 0, 0.0, "", "0", [] và null. Mọi thứ khác đều là true. Bảng dưới đây cho thấy mỗi giá trị cùng kiểu của nó, kết quả chuyển sang bool và có phải dạng số hay không:
| $x | gettype | bool | is_numeric |
|---|---|---|---|
| 0 | |||
| 1 | |||
| -1 | |||
| 0.0 | |||
| 1.5 | |||
| "0" | |||
| "" | |||
| " " | |||
| "0.0" | |||
| "10" | |||
| "1e1" | |||
| "abc" | |||
| "null" | |||
| true | |||
| false | |||
| null | |||
| [] | |||
| [0] |
Những điểm bất ngờ là "0.0", " " và "null": cả ba đều là chuỗi không rỗng và khác "0", nên chúng là true, và if ($value) sẽ chạy phần thân với chúng.
Mảng, đối tượng và null
Mảng chứa bất kỳ tổ hợp giá trị nào dưới các khóa số nguyên hoặc chuỗi. Đối tượng là một instance của một lớp; stdClass là lớp rỗng của PHP để tạo đối tượng nhanh, và (object) biến một mảng thành đối tượng. null có nghĩa là "không có giá trị":
Kiểm tra kiểu bằng các hàm is_*
Mỗi kiểu có một hàm kiểm tra trả về true hoặc false. is_numeric khác với is_int: nó chấp nhận cả chuỗi dạng số, đúng thứ bạn cần khi kiểm tra dữ liệu nhập từ biểu mẫu.
Các hàm khác: is_bool, is_array, is_object, is_null, is_callable, is_iterable, và $x instanceof ClassName cho một lớp cụ thể.
Chuyển kiểu tự động và strict types
PHP tự động chuyển kiểu khi một toán tử cần kiểu khác. Một chuỗi dạng số dùng trong phép tính sẽ thành số, còn . biến số thành chuỗi. Một chuỗi hoàn toàn không phải dạng số thì không cộng được, và PHP 8 ném ra TypeError:
Tham số có khai báo kiểu cũng được chuyển đổi, trừ khi tệp bắt đầu bằng declare(strict_types=1);. Khi đó một lời gọi với kiểu vô hướng sai sẽ thất bại thay vì được chuyển đổi:
Để chủ động chuyển kiểu, hãy ép kiểu: (int) "42", (float) "3.5", (string) 10, (bool) "0". Trang ép kiểu trình bày mọi phép ép kiểu và các trường hợp đặc biệt.
Lỗi thường gặp: so sánh khác kiểu bằng ==
Vì == chuyển kiểu trước khi so sánh, hai giá trị khác kiểu có thể "bằng nhau" theo những cách gây ra bug, như "1e1" == "10" (cả hai đều là số 10) hay null == false. Hãy dùng ===, toán tử này đòi hỏi cả cùng kiểu, trừ khi bạn muốn có phép chuyển kiểu:
PHP 8 đã sửa trường hợp tệ nhất: "abc" == 0 từng là true và giờ là false, vì một chuỗi không phải dạng số được so sánh như chuỗi. Các bảng đầy đủ có ở trang toán tử so sánh.
Câu hỏi thường gặp
Làm sao kiểm tra kiểu của một biến trong PHP?
var_dump($x) in ra kiểu và giá trị, ví dụ int(5). gettype($x) trả về tên kiểu dưới dạng chuỗi ("integer"), còn get_debug_type($x) trả về tên hiện đại ("int", hoặc tên lớp với đối tượng). Để kiểm tra một kiểu cụ thể, dùng is_int, is_string, is_array và các hàm is_* khác.
Vì sao gettype trả về "double" cho số thực?
Vì lý do lịch sử, gettype() gọi số thực là "double" và số nguyên là "integer". get_debug_type(), có từ PHP 8, trả về "float" và "int", đúng những tên bạn viết khi khai báo kiểu.
Những giá trị nào là false trong PHP?
Khi chuyển sang bool, các giá trị sau là false: false, 0, 0.0, "", "0", [] và null. Mọi giá trị khác đều là true, kể cả "0.0", " " và "false".
Số nguyên lớn nhất trong PHP là bao nhiêu?
Là PHP_INT_MAX, bằng 9223372036854775807 trên hệ thống 64-bit. Cộng vượt quá giá trị này không quay vòng: kết quả trở thành số thực và mất độ chính xác.
PHP là ngôn ngữ định kiểu mạnh hay yếu?
PHP định kiểu động và mặc định tự chuyển kiểu khi có thể ("10" + 5 là 15). Khi có declare(strict_types=1); ở đầu tệp, các lời gọi tới hàm có khai báo kiểu trong tệp đó sẽ từ chối kiểu vô hướng sai bằng TypeError thay vì chuyển đổi.