PHP后期静态绑定分析使用详解

这次给大家带来PHP后期静态绑定分析使用详解,PHP后期静态绑定分析使用的注意事项有哪些,下面就是实战案例,一起来看一下。

基础知识

1. 范围解析操作符 (::)

可以用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法。

self,parent 和 static 这三个特殊的关键字是用于在类定义的内部对其属性或方法进行访问的。

parent用于调用父类中被覆盖的属性或方法(出现在哪里,就将解析为相应类的父类)。

self用于调用本类中的方法或属性(出现在哪里,就将解析为相应的类;注意与$this区别,$this指向当前实例化的对象)。

当一个子类覆盖其父类中的方法时,PHP 不会调用父类中已被覆盖的方法。是否调用父类的方法取决于子类。

2. PHP内核将类的继承实现放在了”编译阶段”

  1. <?phpclass A{ const H = 'A'; const J = 'A'; static function testSelf(){ echo self::H; //在编译阶段就确定了 self解析为 A }}class B extends A{ const H = "B"; const J = 'B'; static function testParent(){ echo parent::J; //在编译阶段就确定了 parent解析为A } /* 若重写testSelf则能输出“B”, 且C::testSelf()也是输出“B” static function testSelf(){ echo self::H; } */}class C extends B{ const H = "C"; const J = 'C';}B::testParent();B::testSelf();echo "";C::testParent();C::testSelf();

登录后复制

运行结果:

AA
AA

结论:

self::和parent::出现在某个类X的定义中,则将被解析为相应的类X,除非在子类中覆盖父类的方法。

3.Static(静态)关键字

作用:

– 在函数体内的修饰变量的static关键字用于定义静态局部变量。
– 用于修饰类成员函数和成员变量时用于声明静态成员。
– (PHP5.3之后)在作用域解析符(::)前又表示静态延迟绑定的特殊类。

例子:

定义静态局部变量(出现位置:局部函数中)

特征:静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。

  1. <?phpfunction test(){ static $count = 0; $count++; echo $count; if ($count < 10) { test(); } $count--;}

登录后复制

定义静态方法,静态属性

a)声明类属性或方法为静态,就可以不实例化类而直接访问。

b)静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)

c)如果没有指定访问控制,属性和方法默认为公有。

d)由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。

e)静态属性不可以由对象通过 -> 操作符来访问。

f)用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误。

g)就像其它所有的 PHP 静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。

a.静态方法例子(出现位置: 类的方法定义)

  1.  

登录后复制

b.静态属性例子(出现位置:类的属性定义)

  1. staticValue() . "";print $foo->my_static . ""; // Undefined "Property" my_static print $foo::$my_static . "";$classname = 'Foo';print $classname::$my_static . ""; // As of PHP 5.3.0print Bar::$my_static . "";$bar = new Bar();print $bar->fooStatic() . "";?>

登录后复制

c.用于后期静态绑定(出现位置: 类的方法中,用于修饰变量或方法)

下面详细分析

后期静态绑定(late static binding)

自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类。

1.转发调用与非转发调用

转发调用 :

指的是通过以下几种方式进行的静态调用:self::,parent::,static:: 以及 forward_static_call()。

非转发调用 :

明确指定类名的静态调用(例如Foo::foo())

非静态调用(例如$foo->foo())

2.后期静态绑定工作原理

原理:存储了在上一个“非转发调用”(non-forwarding call)中的类名。意思是当我们调用一个转发调用的静态调用时,实际调用的类是上一个非转发调用的类。

例子分析:

  1. <?phpclass A { public static function foo() { echo CLASS.""; static::who(); } public static function who() { echo CLASS.""; }}class B extends A { public static function test() { echo "A::foo()"; A::foo(); echo "parent::foo()"; parent::foo(); echo "self::foo()"; self::foo(); } public static function who() { echo CLASS.""; }}class C extends B { public static function who() { echo CLASS.""; }}C::test();/* * C::test(); //非转发调用 ,进入test()调用后,“上一次非转发调用”存储的类名为C * * //当前的“上一次非转发调用”存储的类名为C * public static function test() { * A::foo(); //非转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为A,然后实际执行代码A::foo(), 转 0-0 * parent::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处的parent解析为A ,转1-0 * self::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处self解析为B, 转2-0 * } * * * 0-0 * //当前的“上一次非转发调用”存储的类名为A * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为A, 故实际执行代码A::who(),即static代表A,进入who()调用后,“上一次非转发调用”存储的类名依然为A,因此打印 “A” * } * * 1-0 * //当前的“上一次非转发调用”存储的类名为C * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C” * } * * 2-0 * //当前的“上一次非转发调用”存储的类名为C * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C” * } */故最终结果为:A::foo()AAparent::foo()ACself::foo()AC

登录后复制

3.更多静态后期静态绑定的例子

a)Self, Parent 和 Static的对比

  1. selfname() . "";echo $apple->parentname() . "";echo $apple->staticname();?>运行结果:MangoOrangeApple

登录后复制

b)使用forward_static_call()

  1. 运行结果:Orange isOrange is my favorite fruitApple is my father's favorite fruit

登录后复制

c)使用get_called_class()

  1. 运行结果:MangoOrange

登录后复制

应用

前面已经提到过了,引入后期静态绑定的目的是:用于在继承范围内引用静态调用的类。
所以, 可以用后期静态绑定的办法解决单例继承问题。

先看一下使用self是一个什么样的情况:

  1. <?php// new self 得到的单例都为A。class A{ protected static $_instance = null; protected function construct() { //disallow new instance } protected function clone(){ //disallow clone } static public function getInstance() { if (self::$_instance === null) { self::$_instance = new self(); } return self::$_instance; }}class B extends A{ protected static $_instance = null;}class C extends A{ protected static $_instance = null;}$a = A::getInstance();$b = B::getInstance();$c = C::getInstance();var_dump($a);var_dump($b);var_dump($c);运行结果:E:codephp_testpplyself.php:37:class A#1 (0) {}E:codephp_testpplyself.php:38:class A#1 (0) {}E:codephp_testpplyself.php:39:class A#1 (0) {}

登录后复制

通过上面的例子可以看到,使用self,实例化得到的都是类A的同一个对象

再来看看使用static会得到什么样的结果

  1. <?php// new static 得到的单例分别为D,E和F。class D{ protected static $_instance = null; protected function construct(){} protected function clone() { //disallow clone } static public function getInstance() { if (static::$_instance === null) { static::$_instance = new static(); } return static::$_instance; }}class E extends D{ protected static $_instance = null;}class F extends D{ protected static $_instance = null;}$d = D::getInstance();$e = E::getInstance();$f = F::getInstance();var_dump($d);var_dump($e);var_dump($f);运行结果:E:codephp_testpplystatic.php:35:class D#1 (0) {}E:codephp_testpplystatic.php:36:class E#2 (0) {}E:codephp_testpplystatic.php:37:class F#3 (0) {}

登录后复制

相信看了本文案例你已经掌握了方法,更多精彩请关注【创想鸟】其它相关文章!

推荐阅读:

用JS检测电脑配置(附代码)

Vue.js+Flask来构建单页的App(附代码)

以上就是PHP后期静态绑定分析使用详解的详细内容,更多请关注【创想鸟】其它相关文章!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

点点赞赏,手留余香

给TA打赏
共0人
还没有人赞赏,快来当第一个赞赏的人吧!
    编程技术

    不重启Vim重新加载 .vimrc 文件如何实现

    2025-3-8 10:33:08

    编程技术

    JS+PHP动态添加类

    2025-3-8 10:33:15

    0 条回复 A文章作者 M管理员
    欢迎您,新朋友,感谢参与互动!
      暂无讨论,说说你的看法吧
    个人中心
    购物车
    优惠劵
    今日签到
    私信列表
    搜索