Laravel 4.2项目升级PHP7后object_get()助手函数失效排查
我来帮你拆解这个Laravel 4.2的object_get函数在PHP7迁移中遇到的问题,毕竟我也踩过类似的坑😉
object_get在PHP7迁移中的核心问题 首先先补全你没写完的完整函数(对照Laravel 4.2源码):
function object_get($object, $key, $default = null) { if (is_null($key) || trim($key) == '') return $object; foreach (explode('.', $key) as $segment) { if ( ! is_object($object) || ! isset($object->{$segment})) { return $default; } $object = $object->{$segment}; } return $object; }
从PHP5.6切换到PHP7后,这个函数会遇到以下几个关键问题:
1. 非对象属性访问直接抛出致命Error
在PHP5中,如果你尝试访问一个非对象类型(比如字符串、整数、数组)的属性(比如$string->foo),只会抛出E_WARNING警告,然后返回null,函数里的判断会在下一次循环触发,优雅返回默认值。
但在PHP7中,这种操作会直接抛出**Error类型的致命错误**(属于可捕获的Throwable,但原函数没有处理逻辑),直接终止脚本执行,完全无法返回默认值。
举个例子:
$obj = (object) ['username' => 'johndoe']; object_get($obj, 'username.fullname'); // PHP5返回null,PHP7直接报错崩溃
2. isset()无法识别魔术方法动态返回的属性
不管是PHP5还是PHP7,isset($object->{$segment})都会返回false——如果这个属性是通过__get魔术方法动态获取的(比如Laravel Eloquent模型的属性)。但在PHP7的环境下,这个问题会更突出:很多旧项目依赖模型的魔术属性访问,导致object_get错误地返回默认值,而不是实际的属性值。
比如Eloquent模型的$user->name是通过__get访问$user->attributes['name'],但isset($user->name)会返回false,所以object_get($user, 'name')会直接返回默认值,完全不符合预期。
3. 未支持数组类型的嵌套访问
原函数只判断了is_object($object),但Laravel的object_get原本是设计支持数组嵌套的(比如object_get($array, 'user.name'))。在PHP5中,访问数组的属性会返回null并触发警告,函数返回默认值;但在PHP7中同样会抛出致命Error,直接导致函数失效。
针对以上问题,你可以修改object_get函数,让它兼容PHP7的行为:
function object_get($object, $key, $default = null) { if (is_null($key) || trim($key) === '') { return $object; } foreach (explode('.', $key) as $segment) { // 同时处理数组和对象两种嵌套类型 if (is_array($object)) { if (!array_key_exists($segment, $object)) { return $default; } $object = $object[$segment]; } elseif (is_object($object)) { // 兼容魔术属性:检查是否存在属性或__get方法 if (!property_exists($object, $segment) && !method_exists($object, '__get')) { return $default; } // 捕获PHP7中访问非对象属性的Error try { $object = $object->{$segment}; } catch (\Throwable $e) { return $default; } } else { // 既不是数组也不是对象,直接返回默认值 return $default; } } return $object; }
这个修复版本做了这些优化:
- 同时支持数组和对象的嵌套访问
- 捕获PHP7中访问非对象属性的致命Error,优雅返回默认值
- 兼容魔术方法属性的访问逻辑
- 用
array_key_exists替代isset处理数组(避免过滤掉值为null的数组元素)
内容的提问来源于stack exchange,提问作者Jafo

