什么叫后期静态绑定呢?其实我们在之前的文章PHP中的static中已经说过这个东西了。今天我们还是再次深入的理解一下这个概念。

首先,我们通过一段代码来引入后期静态绑定这一概念:

class A
{
public static function who()
{
echo __CLASS__, PHP_EOL;
}
public static function test()
{
self::who();
}
} class B extends A
{
public static function who()
{
echo __CLASS__, PHP_EOL;
}
} B::test(); // A

在这段代码中,我们使用了self关键字,当使用B类调用test()静态方法时,self指向的是A类的who()方法,因此,输出的是A。别激动,这是普通的静态绑定。self关键字调用的内容取决于它定义时所在的类。也就是说不管怎么继承,用哪个子类来调用test()方法,self关键字都会调用的是A类的who()方法。

而后期静态绑定呢?其实就有点像实例化的类对象,每个实例化的对象,调用的都是自身,而不是父类的属性方法。普通的静态调用可不是这样,但是现实中我们又有这样的需求,就像实例化对象的调用方式一样来调用静态属性方法,这时,我们就可以使用static关键字来实现后期静态绑定。

class C
{
public static function who()
{
echo __CLASS__, PHP_EOL;
}
public static function test()
{
static::who();
}
} class D extends C
{
public static function who()
{
echo __CLASS__, PHP_EOL;
}
} D::test(); // D

当使用static关键字后,这里D类调用的test()方法内部调用的who()就是D类自己了。

官方文档中的定义如下:

当进行静态方法调用时,该类名即为明确指定的那个(通常在 :: 运算符左侧部分);当进行非静态方法调用时,即为该对象所属的类。

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

除了self和static关键字外,我们还有一个parent关键字,这个关键字的意义就很明显了,调用父类的静态内容。我们同时用三个关键字一起来进行测试:

class E
{
public static function who()
{
echo __CLASS__, PHP_EOL;
}
public static function test()
{
self::who();
static::who();
}
} class F extends E
{
public static function who()
{
echo __CLASS__, PHP_EOL;
}
} class G extends F
{
public static function who()
{
parent::who();
echo __CLASS__, PHP_EOL;
}
} G::test(); // E
// F
// G

最后,我们再来看两个PHP的方法,一个是get_called_class()方法,用来获取当前调用的是哪个类。在静态方法中可以根据调用方式判断当前类是哪个类来进行其他的业务逻辑操作。另一个是forward_static_call()方法,用于静态方法的调用。

class H
{
public static function who()
{
echo __CLASS__ . ':' . join(',', func_get_args()), PHP_EOL;
}
public static function test()
{
echo get_called_class(), PHP_EOL;
forward_static_call('who', 'a', 'b'); // xxx:a,b
forward_static_call(['I', 'who'], 'c', 'd'); // I:c,d
forward_static_call_array(['H', 'who'], ['e', 'f']); // H:e,f
}
} class I extends H
{
public static function who()
{
echo __CLASS__ . ':' . join(',', func_get_args()), PHP_EOL;
}
} function who()
{
echo 'xxx:' . join(',', func_get_args()), PHP_EOL;
} H::test(); // H
// xxx:a,b
// I:c,d
// H:e,f
I::test(); // I
// xxx:a,b
// I:c,d
// H:e,f

注意,如果forward_static_call()不指定类名的话,将调用全局的方法。forward_static_call_array()则是将参数使用数组进行传递。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202001/source/%E5%90%8E%E6%9C%9F%E9%9D%99%E6%80%81%E7%BB%91%E5%AE%9A%E5%9C%A8PHP%E4%B8%AD%E7%9A%84%E4%BD%BF%E7%94%A8.php

参考文档:

https://www.php.net/manual/zh/language.oop5.late-static-bindings.php

https://www.php.net/manual/zh/function.get-called-class.php

https://www.php.net/manual/zh/function.forward-static-call.php

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

后期静态绑定在PHP中的使用的更多相关文章

  1. 禁用绑定在Repeater的控件

    实例一: 前台: <asp:Repeater ID="rp_bf" runat="server" onitemdatabound="rp_bf_ ...

  2. jQuery1.8以上,ajaxSend,ajaxStart等一系列事件要绑定在document上才有效果

    jQuery1.8以上,ajaxSend,ajaxStart等一系列事件要绑定在document上才有效果

  3. 为什么tap事件绑定在document上,而不是对象本身上

    1.在移动端前端开发,click事件有300ms的延时,为了提升用户体验,快速响应.zepto添加了tap事件.tap是在手指触屏横纵向移动距离小于30px,触发tap事件.移动距离的判断是通过tou ...

  4. 单例模式与静态变量在PHP中

    在PHP中,没有普遍意义上的静态变量.与Java.C++不同,PHP中的静态变量的存活周期仅仅是每次PHP的会话周期,所以注定了不会有Java或者C++那种静态变量. 1. 静态变量在PHP中 在PH ...

  5. 解决QZ-SDK静态库libRPToolLib.a中avfoundation.o文件和kxMovie依赖的ffmpeg静态库libavdevice.a函数重复定义的问题

    解决QZ-SDK静态库libRPToolLib.a中avfoundation.o文件和kxMovie依赖的ffmpeg静态库libavdevice.a函数重复定义的问题 在原来项目中导入全志v3相机的 ...

  6. 在本地运行正常的静态网页放到tomcat中却显示异常的原因

    在本地写好了一个个人网站,本地直接用浏览器运行,很顺利,然而把网站放到Tomcat里面,却发现图片显示不出来,这就奇怪了. 后来发现,我的网站的Image文件夹用了大写“I”,而网页里面的路径用了小写 ...

  7. 2.java中c#中statc 静态调用不同之处、c#的静态构造函数和java中的构造代码块、静态代码块

    1.java和c#静态成员调用的不同之处 static 表示静态的,也就是共享资源,它是在类加载的时候就创建了 java中   可以通过实例来调用,也可以通过类名.成员名来调用,但是一般最好使用类名. ...

  8. jQuery 事件绑定四种方式,delegate委托强大绑定在3.0中修改为on

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 内部类访问外部类的变量必须是final吗,java静态方法中不能引用非静态变量,静态方法中不能创建内部类的实例

    内部类访问外部类的变量必须是final吗? 如下: package com.java.concurrent; class A { int i = 3; public void shout() { cl ...

随机推荐

  1. 管理员权限的窗口,收不到WM_COPYDATA

    windows用户界面特权隔离 一个运行在较低特权等级的应用程序的行为就受到了诸多限制,它不可以: 验证由较高特权等级进程创建的窗口句柄 通过调用SendMessage和PostMessage向由较高 ...

  2. MongoDB-04-备份和恢复

    mongodb备份和恢复 常用的备份恢复工具 1 ** mongoexport/mongoimport 2 ***** mongodump/mongorestore 备份工具区别在哪里 应用场景总结: ...

  3. Java基础技术多线程与并发面试【笔记】

    Java基础技术多线程与并发 什么是线程死锁? ​死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去,我们就可以称 ...

  4. shodan搜索

    扫描一切联网的设备 www.shodan.io 一.ip 直接搜索:123.123.123.123 二.搜索服务 http http country:"DE" 指定搜索德国 htt ...

  5. ECDSA—模乘模块

    如果a,b属于GF(P),则有乘法运算a*b=r (mod p), 其中r满足0<r<p-1,即a*b除以p的余数.该操作成为模p乘法.本模块输入两个数,完成两个数的模乘运算. 信号名 方 ...

  6. NOIP 模拟 $11\; \rm biology$

    题解 首先对 \(a\) 离散化,则可推出转移方程 \[dp_{i,j}=\max\{{dp_{{i^{'}},{j^{'}}}+|i-i^{'}|+|j-j^{'}|}\}+b_{i,j} \;\; ...

  7. FirstGradle

    一.导入依赖 二.build.gradle 整合SpringBoot plugins { id 'java' } group 'com.qiang' version '1.0.0-SNAPSHOT' ...

  8. 编写一个简单的COM组件

    参考网站:编写一个简单的COM组件_a ray of sunshine-CSDN博客 (1) 用MIDL编写.idl文件 //将以下代码保存成 IXIYIZ.idl 文件 //在命令行上进行编译,编译 ...

  9. nginx 实现反向代理、负载均衡、高可用

    转自:https://blog.csdn.net/zy1471162851/article/details/91795712 tip:   nginx是一款高性能的http 服务器/反向代理服务器及电 ...

  10. 使用servlet中是否需要考虑线程问题

    package day09; import java.io.IOException; import javax.servlet.ServletException; import javax.servl ...