PHP 7.2禁止类名为Object的巨坑
2018年1月4日PHP 7.2.1发布,很多之前处于观望的小伙伴开始打算升级PHP了,不过要注意到2017年11月30日发布的PHP 7.2.0开始禁止类名为Object,这将导致很多包出错。特别是很多包的兼容性只写了最低版本,没有写最高版本,使用PHP 7.2的时候composer并不会提示兼容性错误,而PHP的autoload的延迟加载特性,又会导致仅在涉及的时候才会提示错误。例如这样的场景:
程序使用框架F,使用第三方模块M,而模块M中在特定参数的情况会调用模块N,模块N中包含一个类名为Object的类。在开发的时候,模块N并不会涉及到,因此在PHP 7.2中开发很久也不会遇到这个问题。可是给客户部署的时候,出现了使用模块N的情况。
这时候,如果降级到PHP 7.1,那么程序中已经大量使用的PHP 7.2的特性就都需要修改,特别是禁止类名使用Object的特性的根源——Object类型提示,就全部要修改,而且需要增加相应的程序判断。
如果不降级,那么就需要修改模块N中所有涉及到Object的地方,程序员都知道修改别人的代码多么痛苦。
最后说说这个坑。
PHP 7.2.0 Released 中包含 Object typehint 对象类型提示 ,其中提到 Backward Incompatible Changes 向后兼容变更
Although ‘object’ is already a soft reserved word, this RFC adds object as fully reserved classname.
从这里可以看出,object一直是一个软soft保留字,程序中本来就不应该使用,这次只不过变成了完全保留字而已。
例如 yii2 也做了修改 https://github.com/yiisoft/yii2/blob/master/framework/base/Object.php
尽管这么大的坑,不过好处也多多,官方给出的例子如下:
参数类型
function acceptsObject(object $obj) {
...
}
// This code can be statically analyzed to be correct
acceptsObject(json_decode('{}'));
// This code can be statically analyzed to be correct
acceptsObject(new \MyObject());
// This can be statically analysed to contain an error.
// and would throw an TypeError at runtime.
acceptsObject("Ceci n'est pas une object.");返回类型
// This function can be statically analysed to conform to the
// return type
function correctFunction() : object {
$obj = json_decode('{}');
return $obj;
}
// This function can be statically analysed to contain an error
// and will also fail at runtime.
function errorFunction() : object {
return [];
}转换器和数据解析器
interface Hydration {
// Hydrate an object by populating data
public function hydrate(array $data, object $object) : object;
}
interface Extraction {
// Extract values from an object
public function extract(object $object) : array;
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
服务容器和依赖注入容器
interface ServiceContainer {
// Set service definition
public function set(string $id, object $service);
// Retrieve service object from container
public function get(string $id) : object;
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
捕获返回值错误
function unserialize($data) : object {
$type = $data['type'];
switch ($type) {
case 'foo': { return new Foo(); }
case 'bar': { return new Bar(); }
case 'zot': { new zot(); } // Ooops, this is an error
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
继承中强制函数签名
class WidgetFactory {
function create() : object {
return new Widget();
}
}
class CustomWidgetFactory extends WidgetFactory {
// This class would not compile, as the signature of the metod in
// the child class is not compatible with the method signature in
// the parent class.
function create() : bool {
...
}
}- 14
参数类型提示逆变
class Foo {
}
class Bar {
public function foo(Foo $object) : object {
return $object;
}
}
class Baz extends Bar {
public function foo(object $object) : object {
return $object;
}
}- 14
返回值类型协变
class Foo {
}
class Bar {
public function foo(object $object) : object {
return $object;
}
}
class Baz extends Bar {
public function foo(object $object) : Foo {
return $object;
}
}- 14



















