PHP 有八种日常会用到的类型:int、float、string、bool、array、object、null,以及用于传递函数的 callable。变量本身没有固定类型,类型属于它当前的值。var_dump($x) 会同时显示类型和值,gettype($x) 以字符串返回类型。
第一列是 gettype() 的结果,第二列是 get_debug_type() 的结果。把某个值换成你自己的值,再运行一次。两者有几个名字不一样:由于历史原因,gettype 使用 integer、double 和 boolean,而 get_debug_type 使用类型声明中的名字(int、float、bool),对于对象则给出类名。
PHP 类型一览
| 类型 | 示例 | 说明 |
|---|---|---|
int | 42、-7、0x1A、1_000_000 | 整数,在现代系统上为 64 位 |
float | 3.14、1.5e3 | 小数,和其他语言一样不精确 |
string | "hi"、'hi' | 字节序列,而不是字符序列 |
bool | true、false | 不区分大小写(TRUE 也可以) |
array | [1, 2]、["a" => 1] | 有序映射:列表和字典合二为一 |
object | new User()、new stdClass() | 类的实例 |
null | null | null 类型唯一的值,也表示“没有设置值” |
callable | 'strlen'、fn($x) => $x * 2 | 任何可以调用的东西 |
iterable | 数组或 Traversable 对象 | foreach 能接受的值 |
resource | fopen() 的返回结果 | 指向 PHP 外部某个东西的句柄 |
用 var_dump 查看值
var_dump 是查看变量真实内容的工具。它会打印类型和值,对于字符串还会打印以字节为单位的长度:
如果用 echo,前三个都会打印成 10,看不出区别。string(5) "café" 中的长度统计的是字节数,这就是为什么对于非 ASCII 文本,strlen 和 mb_strlen 的结果不同。
整数和浮点数
整数就是没有小数部分的数。字面量中可以用下划线提高可读性,也可以使用十六进制、八进制和二进制写法。浮点数是任何带小数点或指数的数,和其他所有语言一样,大多数小数都只能近似存储:
永远不要用 == 比较浮点数;应该把差值和一个很小的容差比较,或者先把两边都四舍五入。处理金额时,请用整数存储以分为单位的金额。
布尔值以及哪些值为假
bool 的值是 true 或 false。在 PHP 需要条件的地方(if、while、!),任何值都会被转换成布尔值,只有少数几个值算作假:false、0、0.0、""、"0"、[] 和 null。其他所有值都为真。下面的表格列出了每个值的类型、转换成布尔值的结果,以及它是否为数字:
| $x | gettype | bool | is_numeric |
|---|---|---|---|
| 0 | |||
| 1 | |||
| -1 | |||
| 0.0 | |||
| 1.5 | |||
| "0" | |||
| "" | |||
| " " | |||
| "0.0" | |||
| "10" | |||
| "1e1" | |||
| "abc" | |||
| "null" | |||
| true | |||
| false | |||
| null | |||
| [] | |||
| [0] |
出人意料的是 "0.0"、" " 和 "null":这三个都是非空字符串,又都不是 "0",所以它们为真,if ($value) 会执行其中的代码。
数组、对象和 null
数组可以在整数键或字符串键下存放任意类型的值。对象是类的实例;stdClass 是 PHP 用来快速创建对象的空类,(object) 可以把数组转换成对象。null 表示“没有值”:
用 is_* 函数检查类型
每种类型都有一个返回 true 或 false 的检测函数。is_numeric 和 is_int 不同:它也接受数字字符串,检查表单输入时正需要这一点。
其他的还有:is_bool、is_array、is_object、is_null、is_callable、is_iterable,以及用于检查具体类的 $x instanceof ClassName。
类型转换和严格类型
当运算符需要另一种类型时,PHP 会自动转换类型。数字字符串参与算术运算时会变成数字,. 会把数字变成字符串。完全不是数字的字符串不能参与加法,PHP 8 会抛出 TypeError:
带类型的参数也会进行转换,除非文件以 declare(strict_types=1); 开头。这时,传入错误标量类型的调用会直接失败,而不会被转换:
要主动转换类型,就进行强制转换:(int) "42"、(float) "3.5"、(string) 10、(bool) "0"。类型转换页面讲解了每一种强制转换及其边界情况。
常见错误:用 == 比较不同类型的值
因为 == 会先转换再比较,两个不同类型的值可能会以引发 bug 的方式“相等”,例如 "1e1" == "10"(两者都是数字 10)或 null == false。除非你需要转换,否则请使用 ===,它还要求类型相同:
PHP 8 修复了最糟糕的情况:"abc" == 0 以前是 true,现在是 false,因为非数字字符串会按字符串比较。完整的对照表见比较运算符页面。
常见问题
PHP 中怎么检查变量的类型?
var_dump($x) 会打印类型和值,例如 int(5)。gettype($x) 以字符串返回类型名称("integer"),get_debug_type($x) 返回现代的名称("int",对象则返回类名)。要判断是否为某一种类型,使用 is_int、is_string、is_array 以及其他 is_* 函数。
为什么 gettype 对浮点数返回 "double"?
由于历史原因,gettype() 把浮点数报告为 "double",把整数报告为 "integer"。PHP 8 新增的 get_debug_type() 返回 "float" 和 "int",和你在类型声明中写的名字一致。
PHP 中哪些值是 false?
转换成布尔值后,下面这些值是 false:false、0、0.0、""、"0"、[] 和 null。其他所有值都是 true,包括 "0.0"、" " 和 "false"。
PHP 中最大的整数是多少?
是 PHP_INT_MAX,在 64 位系统上为 9223372036854775807。超过它之后不会回绕:结果会变成浮点数,并丢失精度。
PHP 是强类型还是弱类型语言?
PHP 是动态类型语言,默认情况下会尽量自动转换类型("10" + 5 是 15)。在文件顶部写上 declare(strict_types=1); 后,该文件中对带类型函数的调用如果传入了错误的标量类型,就会抛出 TypeError,而不是进行转换。