去年就在《深入PHP面向对象、模式与实践》中看到了这样的一种用法,今天才拿出来仔细分析。
如果我们懒得思考会这么写:
<?php
abstract class DomainObject{
}
class User extends DomainObject{
public static function create(){
return new User();
}
}
class Document extends DomainObject{
public static function create(){
return new Document();
}
}
也可能这么写
<?php
abstract class DomainObject{
}
class User extends DomainObject{
public static function create(){
return new self();
}
}
class Document extends DomainObject{
public static function create(){
return new self();
}
}
运行起来是没有任何问题的,但是作为程序员的我们对重复部分是难以忍受的。
我们沿着self继续往下想,会这么写
<?php
abstract class DomainObject{
public static function create(){
return new self();
}
}
class User extends DomainObject{
}
class Document extends DomainObject{
}
Document::create();
但是我们看一下输出结果:
出现了上面这样的错误,我先写正确代码,然后再解释原因:
<?php
abstract class DomainObject{
public static function create(){
return new static();
}
}
class User extends DomainObject{
}
class Document extends DomainObject{
}
Document::create();
self指的不是调用上下问,指的是解析上下文,self会被解析为抽象类中的方法,而不是调用者中的方法。这里我们就用到了延迟绑定,static直接指向的是调用者而不是抽象方法中。
我这样写有人会考虑到是不是只有抽象方法中才会有这样的情况,这个问题请大家自行测试。要特别提醒你的php版本要大于php5.3才会有这样的功能。
ok!看自我内部调用的情况:
<?php
abstract class DomainObject{
private $group;
public function __construct(){
$this->group = static::getGroup();
}
public static function create(){
return new static();
}
static function getGroup(){
return 'default';
}
}
class User extends DomainObject{
}
class Document extends DomainObject{
static function getGroup(){
return 'document';
}
}
var_dump(User::create());
var_dump(Document::create());
结果:
object(User)[1]
private 'group' (DomainObject) => string 'default' (length=7)
object(Document)[1]
private 'group' (DomainObject) => string 'document' (length=8)
实际上static和self使用基本相同,不同就是调用时候,指向的是自己自身的属性和方法,而不是被定义位置的方法属性。处理php版本的影响外,这样情况比多些很多代码要强。