PHP子类未调用父类构造函数时,父类公共属性的初始化逻辑疑问
PHP子类未调用父类构造函数时,父类公共属性的初始化逻辑疑问
我完全理解你的困惑,当初我第一次碰到这种情况时也一脸懵——明明没调用父类构造函数,也没给$x、$y赋值,怎么既没报错还输出了(0,0,3)?咱们一步步拆解背后的逻辑:
1. 子类构造函数不会自动触发父类构造
PHP的默认规则是:子类定义了自己的构造函数后,不会自动调用父类的构造函数。只有当你在子类构造里显式写parent::__construct($x, $y)时,父类的构造逻辑才会执行。
所以你的Point3D实例中,$x和$y确实没有被父类的构造函数初始化,它们的初始值是PHP类成员属性的默认值——null(只要在类里声明了属性,哪怕没赋值,它也属于已声明的成员,访问时不会报错)。
2. sprintf的整数格式化会强制类型转换
你用了sprintf('(%d, %d, %d)', $p->x, $p->y, $p->z),这里的%d是整数类型的格式化符。PHP在处理类型不匹配的参数时,会做自动类型转换:
null会被强制转换成整数0;- 空字符串、非数字字符串也会被转成
0; - 只有合法的数字内容才会转成对应整数。
所以$x和$y的null被转成了0,$z是你赋值的3,最终就输出了(0,0,3)。
3. 为什么不会触发致命错误?
你和ChatGPT误以为会报错,大概率是混淆了「未声明的普通变量」和「已声明但未赋值的类成员属性」:
- 如果你直接访问一个从没声明过的普通变量(比如
echo $undefined;),PHP会抛出警告(PHP8+是Error级别); - 但
$x、$y是在父类Point里已经明确声明的公共属性,哪怕没赋值,访问它也是完全合法的操作,只会返回默认的null,不会触发致命错误。
你可以做个小验证:把echo sprintf(...)改成var_dump($p->x, $p->y, $p->z);,运行后会看到输出:
NULL NULL int(3)
这就能直观看到这两个属性的实际值了。
总结一下:核心就是两个关键点——类成员未赋值时默认是null,以及sprintf的%d会把null转成0,同时访问已声明的类属性哪怕未赋值也不会报错。
备注:内容来源于stack exchange,提问作者StarNab
相关产品推荐
相关产品推荐

