什么叫后期静态绑定呢?其实我们在之前的文章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. pip的问题 Can't connect to HTTPS URL because the SSL module is not available

    pip is configured with locations that require TLS/SSL, however the ssl module in Python is not avail ...

  2. kafka查看Topic列表及消费状态等常用命令

    环境 本文中的操作均基于kafka_1.3.3.0,且所有命令经过实际验证. 常用工具 新建Topic ./kafka-topics --zookeeper 166.188.xx.xx --creat ...

  3. COM组件的使用方法

    https://prismlibrary.com/docs/wpf/converting-from-7.html Requirement: 1.创建myCom.dll,该COM只有一个组件,两个接口I ...

  4. mysql几种连接方式区别

    mysql的几种join 2017年03月19日 14:49:07 carl-zhao 阅读数:7845 标签: mysqlsqljoin 更多 个人分类: MySQL 版权声明:本文为博主原创文章, ...

  5. c# button Command

    internal class DelegateCommand : ICommand { private readonly Action _execute; private readonly Func& ...

  6. jsp中核心标签使用

    <%@ page language="java" import="java.util.*, java.lang.*" pageEncoding=" ...

  7. ObjectInputStream和ObjectOutputStream

    package stream.object; import java.io.FileInputStream; import java.io.FileOutputStream; import java. ...

  8. springboot使用redis(从配置到实战)

    概述 springboot通常整合redis,采用的是RedisTemplate的形式,除了这种形式以外,还有另外一种形式去整合,即采用spring支持的注解进行访问缓存. 准备工作 pom.xml ...

  9. Flink的CheckPoint

    Checkpoint checkpoint是Flink容错的核心机制.它可以定期的将各个Operator处理的数据进行快照存储(Snapshot). 如果Flink程序出现宕机,可以重新从这些快照中恢 ...

  10. git所遇到的问题

    出现这种情况,或 ERROR: Repository not found. fatal: 无法读取远程仓库. 解决办法如下: 1.先输入$ git remote rm origin(删除关联的orig ...