php5.3后静态绑定用法详解


Posted in PHP onNovember 11, 2016

本文实例讲述了php5.3后静态绑定用法。分享给大家供大家参考,具体如下:

手册原文:

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

准确说,后期静态绑定工作原理是存储了在上一个"非转发调用"(non-forwarding call)的类名。当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分);当进行非静态方法调用时,即为该对象所属的类。所谓的"转发调用"(forwarding call)指的是通过以下几种方式进行的静态调用:self::,parent::,static:: 以及 forward_static_call()。可用 get_called_class() 函数来得到被调用的方法所在的类名,static:: 则指出了其范围

该功能从语言内部角度考虑被命名为"后期静态绑定"。"后期绑定"的意思是说,static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为"静态绑定",因为它可以用于(但不限于)静态方法的调用。

self:: 的限制

使用 self:: 或者 __CLASS__ 对当前类的静态引用,取决于定义当前方法所在的类:

Example #1 self:: 用法

<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>

以上例程会输出:

A

后期静态绑定的用法 后期静态绑定本想通过引入一个新的关键字表示运行时最初调用的类来绕过限制。简单地说,这个关键字能够让你在上述例子中调用 test() 时引用的类是 B 而不是 A。最终决定不引入新的关键字,而是使用已经预留的 static 关键字。

Example #2 static:: 简单用法

<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // 后期静态绑定从这里开始
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>

以上例程会输出:

B

Note: 在非静态环境下,所调用的类即为该对象实例所属的类。由于 $this-> 会在同一作用范围内尝试调用私有方法,而 static:: 则可能给出不同结果。另一个区别是 static:: 只能用于静态属性。

Example #3 非静态环境下使用 static::

<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() will be copied to B, hence its scope will still be A and
* the call be successful */
}
class C extends A {
private function foo() {
/* original method is replaced; the scope of the new one is C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test(); //fails
?>

以上例程会输出:

success!
success!
success!
Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9

Note: 后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。另一方面,如果静态调用使用 parent:: 或者 self:: 将转发调用信息。

Example #4 转发和非转发调用

<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>

以上例程会输出:

A
C
C

下面示例分析了基于PHP后期静态绑定功能解决在继承范围内引用静态调用的类。

先看如下代码:

class Person
{
public static function status()
{
self::getStatus();
}
protected static function getStatus()
{
echo "Person is alive";
}
}
class Deceased extends Person
{
protected static function getStatus()
{
echo "Person is deceased";
}
}
Deceased::status(); //Person is alive

很明显,结果不是我们预期的,这是因为self::取决于定义时所在的类,而不是运行中的类。为了解决这个问题,你可能会在继承类中重写status()方法,更好的解决方案是PHP 5.3后添加了后期静态绑定的功能。

代码如下:

class Person
{
public static function status()
{
static::getStatus();
}
protected static function getStatus()
{
echo "Person is alive";
}
}
class Deceased extends Person
{
protected static function getStatus()
{
echo "Person is deceased";
}
}
Deceased::status(); //Person is deceased

可见,static::不在指向当前所在的类,实际上,它是在运行中计算的,强制获取最终类的所有属性。

因此,建议,以后不要再使用self::,使用static::

补充:

网友帖1

php的后期静态绑定,怎么解释?下面的这幅图输出是A,C,C

php5.3后静态绑定用法详解

由图的继承关系可知:C彻底包含了B和A。

在看答案结果以前,他细观察发现,三个类里都有同一个名称who()方法。
系统会用最后一个优先级最高,进一步的说,你几乎没法通过C去调用A、B内的who(),只能重改方法,比如添加个getBWho(){echo B::who();}
然后通过C::getBWho();来调用B内的who();

下面来看运行结果:

test只在B中出现,所以结果必然是test()中运行的三个结果:

第一个:静态直接指名到姓的调用A内静态函数,这没有悬念,必然是A
第二个:parent::是调用上一级的父类,在此题中为A,A中又直接调用static:who();上面说过了,这个who()优先级最高的在C里面,无论在你ABC中哪里调用,只要是static::who()必然是最后定义的那个,覆盖效应,如果想调用A里的必需指明A::who()或是通过去除static从作用域限制来实现。所以这个who()就是C中定义的who
第三个:self::who与第二个类似的问题,看样该走B的,注意覆盖效应,要想调用B内的who必须得B::who(),因为更高级的C已经重写了这个方法,如果C中没有who,肯定就是B,依次类推。所以必然还是调用C中的who;

所以答案为:ACC

代码如下:

<?php
class A {
  public static function foo() {
    static::who();
  }
  public static function who() {
    echo __CLASS__."\n";
  }
}
class B extends A {
  public static function test() {
    A::foo();
    parent::foo();
    self::foo();
  }
  public static function who() {
    echo __CLASS__."\n";
  }
}
class C extends B {
  //public static function who() {
  //  echo __CLASS__."\n";
  //}
}
C::test();
?>

输出为:A B B

网友帖2

(还是针对上面图中的代码)

手册不是说得很清楚么

”后期绑定“的意思是说,static::不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为”静态绑定“,因为它可以用于(但不限于)静态方法的调用。

#1说的有个小问题

【self::foo(); // 这个self实际上是C类。明白吗? C::test() C继承了B的test()方法】

不准确,self还是B类,但是本身没有覆写foo方法,所以就调用父类A的foo方法。

如果self实际是C类,那你试下self::foo();改成self::who();,应当打印C,但是打印B,这也正是self和static的区别。

<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>

输出为:A C B

网友帖3

A::foo(); //A指代A类,访问A类的foo方法和who方法
parent::foo();//调用B类的父类——A的foo方法,并告诉foo方法最原始的调用者是C
self::foo(); //self指代定义该方法的类,即B,但是B没有定义foo方法,它将原始的调用者C向上传递,
// 访问父类的foo方法,最后访问c的who方法;

所以这就回答了楼上的疑问:若是把self::foo(); 改成self::who(),因为self指代B,而B有who方法,所以结果是变成了B

静态调用使用 parent:: 或者 self:: 将转发原始调用信息。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP的开发框架的现状和展望
Mar 16 PHP
php设计模式 Decorator(装饰模式)
Jun 26 PHP
php获取通过http协议post提交过来xml数据及解析xml
Dec 16 PHP
解析php做推送服务端实现ios消息推送
Jul 01 PHP
解析将多维数组转换为支持curl提交的一维数组格式
Jul 08 PHP
php curl基本操作详解
Jul 23 PHP
ThinkPHP 3.2 数据分页代码分享
Oct 14 PHP
PHP实现微信网页授权开发教程
Jan 19 PHP
PHP获取指定时间段之间的 年,月,天,时,分,秒
Jun 05 PHP
PDO::errorCode讲解
Jan 28 PHP
通过PHP实现获取访问用户IP
May 09 PHP
PHP中echo与print区别点整理
Mar 09 PHP
php基于curl实现的股票信息查询类实例
Nov 11 #PHP
PHP中STDCLASS用法实例分析
Nov 11 #PHP
php遍历替换目录下文件指定内容的方法
Nov 10 #PHP
php实现有序数组打印或排序的方法【附Python、C及Go语言实现代码】
Nov 10 #PHP
PHP数组生成XML格式数据的封装类实例
Nov 10 #PHP
Linux平台php命令行程序处理管道数据的方法
Nov 10 #PHP
PHP中功能强大却很少使用的函数实例小结
Nov 10 #PHP
You might like
PHP技术开发技巧分享
2010/03/23 PHP
QQ互联一键登录审核不通过的解决方案
2014/09/10 PHP
弹出模态框modal的实现方法及实例
2017/09/19 PHP
laravel框架分组控制器和分组路由实现方法示例
2020/01/25 PHP
JavaScript 字符串与数组转换函数[不用split与join]
2009/12/13 Javascript
js hover 定时器(实例代码)
2013/11/12 Javascript
js设置文本框中焦点位置在最后的示例代码(简单实用)
2014/03/04 Javascript
JS折半插入排序算法实例
2015/12/02 Javascript
js表单提交和submit提交的区别实例分析
2015/12/10 Javascript
基于Jquery和html5实现炫酷的3D焦点图动画
2016/03/02 Javascript
JavaScript学习小结之被嫌弃的eval函数和with语句实例详解
2016/08/01 Javascript
基于MVC+EasyUI的web开发框架之使用云打印控件C-Lodop打印页面或套打报关运单信息
2016/08/29 Javascript
vue.js入门教程之基础语法小结
2016/09/01 Javascript
利用AngularJs实现京东首页轮播图效果
2016/09/08 Javascript
javascript中活灵活现的Array对象详解
2016/11/30 Javascript
Angular 实现输入框中显示文章标签的实例代码
2018/11/07 Javascript
用node撸一个监测复联4开售短信提醒的实现代码
2019/04/10 Javascript
亲自动手实现vue日历控件
2019/06/26 Javascript
vue+elementUI实现图片上传功能
2019/08/20 Javascript
微信小程序实现横向滚动导航栏效果
2019/12/12 Javascript
vue路由权限校验功能的实现代码
2020/06/07 Javascript
Python解析nginx日志文件
2015/05/11 Python
Python利用ElementTree模块处理XML的方法详解
2017/08/31 Python
详解Appium+Python之生成html测试报告
2019/01/04 Python
Python-接口开发入门解析
2019/08/01 Python
python3 正则表达式基础廖雪峰
2020/03/25 Python
python 一维二维插值实例
2020/04/22 Python
python exit出错原因整理
2020/08/31 Python
利用CSS3动画实现圆圈由小变大向外扩散的效果实例
2018/09/10 HTML / CSS
浅谈html5标签css3的常用样式
2016/10/20 HTML / CSS
PUMA官方商城:世界领先的运动品牌之一
2016/11/16 全球购物
机电专业个人自荐信格式模板
2013/09/23 职场文书
一名毕业生的自我鉴定
2013/12/04 职场文书
葡萄牙语专业个人求职信
2013/12/10 职场文书
借钱欠条怎么写
2015/07/03 职场文书
Nginx虚拟主机的搭建的实现步骤
2022/01/18 Servers