您的位置:首页 > 编程语言 > PHP开发

PHP面向对象:延迟静态绑定(static关键字)

2015-11-08 14:27 531 查看
最近看到了PHP面向对象中的延迟静态绑定这块,注意:php5.3之前没有引入延迟静态绑定,所以版本较低的童鞋可能用不了。

这里我们用一个简单的工厂方法(生成包含类的实例的一种方法)来说明

//定义一个抽象方法作为父类
abstract class ParentClass{
//....
}
//子类User
class User extends ParentClass{
//定义一个静态方法来生成返回一个类实例
public static function create(){
return new User();
}
}
//子类Animal
class Animal extends ParentClass{
public static function create(){
return new Animal();
}
}

//使用:
print_r(User::create());
print_r(Animal::create());

//返回:
User Object ( )
Animal Object ( )


从返回结果上看,我们取得了两个子类的实例,说明这个工厂方法正常的工作了。但是,假如我假如Document、Plant等子类呢?我们要重写很多create()方法!这个很烦人!既然create()方法都是类似的,我把这个方法放到父类中怎么样?

abstract class ParentClass{
//定义一个静态方法来生成返回一个类实例
public static function create(){
return new self();
}
}
//子类User
class User extends ParentClass{
//...
}
//子类Animal
class Animal extends ParentClass{
//...
}

//使用:
print_r(User::create());
print_r(Animal::create());

//返回:
Fatal error: Cannot instantiate abstract class ParentClass in....


返回的结果:不能实例化ParentClass这个抽象类!

好,我们把抽象abstract去掉:

class ParentClass{
//定义一个静态方法来生成返回一个类实例
public static function create(){
return new self();
}
}
//返回结果:
ParentClass Object ( )
ParentClass Object ( )


去掉abstract前后都足以证明:self()调用的是基类本身。

也就不能把create()放在父类中?错!

PHP5.3之后引入了延迟静态绑定的概念。该特性最明显的标志就是新关键字static(静态)。static类似于self,但它表示的是被调用的类而不是包含类。现在我们用 static() 替换 self() :

abstract class ParentClass{
//定义一个静态方法来生成返回一个类实例
public static function create(){
return new static();
}
}
//子类User
class User extends ParentClass{
//...
}
//子类Animal
class Animal extends ParentClass{
//...
}

//使用:
print_r(User::create());
print_r(Animal::create());

//返回:
User Object ( )
Animal Object ( )


我们暂时可以这样理解:self()只能父类中起作用,只会紧跟在所在类中,固定的,而static()灵活性更强,谁调用我,我就是在谁那里起作用,被子类继承下来,那就是指的是子类。在本类中,self()指的是ParentClass,而对于static(),子类User调用我,我就是指User类。当然,通过ParentClass类的对象调用create(),static()指的就是ParentClass类了

关于static关键字,它不仅可以用于实例化所在类,和self和parent一样,static还可以调用类里面的方法:

//这里先用self
class ParentClass{
public $order;
//构造函数
function __construct(){
$this->order = self::getOrder();//调用本类的getorder()方法
}
//延迟静态绑定
public static function create(){
return new static();
}
public function getOrder(){
return "ParentClass";
}
}
class User extends ParentClass{
//重写getOrder()方法
public function getOrder(){
return "User";
}
}
class Animal extends ParentClass{
//重写getOrder()方法
public function getOrder(){
return "Animal";
}
}
//使用:
print_r(User::create());
print_r(Animal::create());
//返回结果:
User Object ( [order] => ParentClass )
Animal Object ( [order] => ParentClass )


结果也说明了,self关键字只能父类中起作用,只会紧跟在所在类中,

我们把self换成static:

class ParentClass{
public $order;
//构造函数
function __construct(){
$this->order = static::getOrder();//调用本类的getorder()方法
}
public static function create(){
return new static();
}
public function getOrder(){
return "ParentClass";
}
}

//使用:
print_r(User::create());
print_r(Animal::create());
//返回结果:
User Object ( [order] => User )
Animal Object ( [order] => Animal )


看结果,static成功的调用了子类中的getOrder()方法!

现在我比较喜欢拿C#和PHP作对比。。。。

在这里,我感觉这跟C#中的运行时多态比较相似(多态后面给大家介绍,这里先用了)

//动物类:父类
public class Animal
{
public int age;//年龄
public double weight;//体重
//吃方法:虚方法
public virtual string Eat()
{
return "Animal Eat";
}
public virtual string Sleep()
{
return "Animal Sleep";
}
}
//狗类:子类
public class Dog : Animal
{
//覆写虚方法
public override string Eat()
{
return "Dog Eat";
}
public override string Sleep()
{
return "Dog Sleep";
}
}
public class Bird : Animal
{
public override string Eat()
{
return "Bird Eat";
}
public override string Sleep()
{
return "Bird Sleep";
}
}
//使用:
Animal al1 = new Dog();
Animal al2 = new Bird();
Console.WriteLine(al1.Sleep());
Console.WriteLine(al2.Sleep());
Console.ReadLine();

//输出结果:
Dog Sleep
Bird Sleep


假如我把Dog类中的覆写Sleep()方法去掉

public class Dog : Animal
{
//覆写虚方法
public override string Eat()
{
return "Dog Eat";
}
}

//返回结果:
Animal Sleep
Bird Sleep


运行时多态(virtual 和 override 关键字):当用子类实例化父类的时候,通过判断对象的类型来决定执行哪个类中的哪个方法,在这里:Animal al1 = new Dog();

al1的类型是Animal,然后去Animal类里面找Sleep()方法,但是,当发现Sleep()方法是个虚方法,到Dog()里面看看该方法有没有被覆写,假如被覆写了,调用覆写后的方法,不然调用虚方法。

这就好比PHP中的延迟静态绑定中的 self 和 static 关键字,假如子类中有覆写(override)父类的虚方法,就相当于使用 static,没有覆写就相当于使用 self。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: