PHP 7.1 对象转数组函数未失效,但 PHP 8.x 因语义更严格、错误提示更明确、运行时检查更深入,导致强制转换键名含不可见字符、get_object_vars() 仅返回 public 属性、json_encode 对不可序列化类型拦截更激进、反射需 setAccessible(true) 等问题。

PHP 7.1 对象转数组函数本身没有“失效”,但很多开发者在升级到 PHP 8.x(尤其是 8.2+)后遇到转换结果异常、键名乱码、空数组、或 json_encode 报错等问题——根源不在函数被删除,而在于语义边界更严格、错误提示更明确、运行时检查更深入。下面直击高频踩坑点和对应解法。
强制转换 (array) 看似正常,但键名含不可见字符
用 $arr = (array)$obj 后 isset($arr['name']) 返回 false?foreach 遍历时键名显示为空或乱码?这不是函数失效,而是 protected/private 属性的键名实际包含不可见的 null 字符(\0):
- public 属性 → 键名就是
'name' - protected 属性 → 实际键名是
"\0*\0name"(注意开头两个字节) - private 属性 → 实际键名是
"\0ClassName\0name"(含完整类名和 null 字符)
PHP 7.1 到 8.4 都保持该行为,但 PHP 8 默认启用更严格的错误报告,var_dump() 显示时可能截断或渲染异常,导致误判为“没转成功”。调试时务必用 bin2hex(key($arr)) 或 printf("'%s'\n", key($arr)); 查看真实键名。
get_object_vars() 返回空数组,不是 bug 是设计
调用 get_object_vars($obj) 却得到 []?别急着换方法——它本就只读取当前作用域下可直接访问的 public 属性,且不触发 __get()、不读取动态属性、不继承父类 private 属性。
立即学习“PHP免费学习笔记(深入)”;
- 若类中所有属性都是
protected或private,返回必为空 - 若用了
__set()/__get()模拟属性,它完全无视这些逻辑 - PHP 8 并未改变此行为,但因类型声明更严,若传入非对象(如
null),会抛TypeError而非静默返回false
适用场景很明确:API 响应只暴露 public 字段、表单映射只取显式定义的字段。别指望它“猜出”你想要什么。
json_encode/json_decode(true) 突然返回 null 或 false
原来好好的代码,在 PHP 8.1+ 升级后 json_decode(json_encode($obj), true) 返回 null 或空数组?大概率是遇到了不可序列化类型被拦截:
- PHP 8 对
resource(如文件句柄、MySQL 连接)、Closure(匿名函数)、循环引用的检测更激进,json_encode()直接返回false -
DateTime、SimpleXMLElement等对象虽能 encode,但默认转成字符串,丢失原始结构;若类未实现JsonSerializable,且含自定义对象,也会中断 - PHP 7.1 允许部分“尽力而为”,PHP 8 要求明确契约:要么可 JSON 化,要么显式处理
安全写法必须加判断:
if (!$json = json_encode($obj)) { throw new RuntimeException('Object contains unserializable data'); }
再执行 json_decode($json, true)。
ReflectionClass 读取 private/protected 属性却报错
用反射读属性时抛 ReflectionException: Cannot access private property?不是 PHP 8 封禁了反射,而是默认不设可访问性:
-
$prop->getValue($obj)要求属性已设为可访问:$prop->setAccessible(true) - PHP 8.2+ 对动态属性(未声明却赋值的属性)发出
E_DEPRECATED警告,若代码依赖$obj->undefined_prop = 'x'再反射读取,会提前报错 - 反射读取时若属性值本身含资源或闭包,仍会导致后续操作失败——它只是“读出来”,不解决序列化问题
推荐组合:反射 + setAccessible(true) + 类型过滤(跳过 resource/Closure),比盲目强转更可控。



















