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

7 篇文章 0 订阅
4 篇文章 0 订阅

最近看到了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。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值