PHP变量类型转换本质是修改zval.type字段并更新value union数据,如字符串"123"转整型时调用convert_to_long()解析内容、存入lval、改type为IS_LONG;隐式与显式转换共用同一底层函数,失败时返回0不报错。

PHP变量类型转换靠修改zval.type字段实现
PHP所有变量都封装在zval结构体里,其中type字段(zend_uchar)直接标记当前类型,比如IS_LONG、IS_STRING、IS_BOOLEAN。类型转换的本质,就是运行时改写这个字段,并同步调整value union 中对应位置的数据。
例如$a = "123"时,zval.type设为IS_STRING,value.str指向字符串内存;执行(int)$a后,Zend引擎调用convert_to_long()函数,解析字符串内容,把结果存进value.lval,再把zval.type改为IS_LONG——旧字符串内存若无其他引用,会被垃圾回收。
- 隐式转换(如
"5" + 3)触发convert_to_long()或convert_to_double() - 显式转换(如
(float)$x)同样走同一套底层函数,只是调用路径不同 - 转换失败时(如
(int)"abc"),convert_to_long()返回0,不报错也不抛异常
字符串转整数时的截断逻辑容易被忽略
PHP对字符串转整数不是“尝试解析”,而是“从左到右扫描直到非数字字符”。这和JavaScript的parseInt()行为完全不同,也不同于C的strtol()。
比如(int)"123abc"结果是123,(int)"abc123"结果是0,(int)"-42px"结果是-42。这种设计源于Zend引擎早期为Web表单输入快速适配的妥协,至今未改。
立即学习“PHP免费学习笔记(深入)”;
- 空格开头会被跳过:
(int)" 42"→42 - 十六进制前缀
0x不识别:(int)"0xff"→0(必须用hexdec()) - 科学计数法字符串(如
"1e3")不会被当作数字解析,结果仍是1
布尔转换的陷阱:null、空数组、空对象全转为false
PHP中bool是标量类型,但判断真假时会触发隐式转换。规则不是“非空即真”,而是有一套硬编码映射表:
null、0、0.0、""、array()、false → true以外全视为false;但"0"是个特例——它被当成字符串,经convert_to_boolean()后结果是false。
-
if ("0") { }块不会执行,这点常让开发者困惑 -
empty("0")返回true,但isset("0")返回true(因为字符串非null) - 对象只要存在(哪怕没属性),
(bool)new StdClass()永远是true
浮点数转整数会直接截断,不是四舍五入
(int)3.9得到3,(int)-3.9得到-3——这是C语言(long)强制转换的直接复现,不是PHP特有逻辑。Zend引擎调用zend_dval_to_lval(),底层就是(long)val cast。
如果需要四舍五入,必须显式调用round();如果要向下取整,用floor();向上取整用ceil()。直接(int)只做截断,且对负数不改变符号位。
-
(int)PHP_INT_MAX + 1.0可能溢出成-9223372036854775808(取决于平台) -
intval()函数行为与(int)完全一致,二者无区别 - 浮点精度误差叠加后截断,比如
(int)(0.1 + 0.2)实际是(int)0.30000000000000004→0



















