php教程,类静态方法可以使用什么调用方式?有何不同?
发布于 作者:苏南大叔 来源:程序如此灵动~
本文聚焦于php类中的静态方法的调用方式,涉及的内容有::和->的使用,以及static::、self::、parent::的区别。同时涉及了一个“后期静态绑定”的概念。如何理解这个“后期静态绑定”的概念呢?请阅读本文的内容。

苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程经验总结。本文测试环境:win10,nginx@1.15.11,php@8.2.10-nts。
基本概念
本文涉及到了__CLASS__以及get_class()等概念,但是它们并不是本文的主角,而是用于验证本文关于 “static::、self::、parent::的区别”的结论的。
| 名称 | 内容 |
|---|---|
| CLASS | 当前的代码所在的实际的类 |
| get_class() | 当前的代码所在的实际的类 |
| get_called_class() | 获得后期静态绑定("Late Static Binding")类的名称。 |
| get_parent_class() | 获得对象或者类的父类名字 |
如果您不是很清楚相关概念的话,可以参考下面这篇文章:
类外部,class::method() 和 class->method()
这个实际上说的是外部调用方法的形式。
在本文中,
在类定义外部,使用::或者->都可以合理的调用静态方法,并不会产生任何结果上的不同。但是推荐使用::这种表述方式。
对于非静态方法,是不可以使用::表述的,直接报错。报错信息类似如下:
Deprecated: Non-static method S::test() should not be called statically| 调用方式 | 说明 |
|---|---|
| class::method() | method()必须是静态方法 |
| class->method() | method()可能是静态方法,也可能是非静态方法 |
所以,对于定义在类里面的静态方法,实际上有三种调用方式。比如:
classs S {
public static function test(){}
}调用方式可以是:
S::test();$s = new S();
$s->test();
$s::test();方法内部,static::、self::、parent::
对于static::、self::、parent::这三种表达来说,都是::的表述,没有->的表述方式。而且也都是用于方法定义内部的,而不是类定义的外部。
| 名称 | 内容 |
|---|---|
| static::method() | 后期静态绑定,实际上就是考虑继承,继承类的method()可以覆盖父类的同名方法 |
| self::method() | 不考虑继承,就是执行当前类定义中的method(),也就是说子类的同名方法覆盖失效【?】 |
| parent::method() | 自身及子类的同名方法都失效,执着的执行父类中的对应方法【?】 |
| class::method() | 直接指明类名,不考虑任何继承或者覆盖之类的概念 |
| $this::method() | 伪命题,静态方法没有上下文,所以也没有$this的表述 |
可见:static::method()就是加了个前缀,然后起了一个新名字(后期静态绑定),实际上的概念还是大家以及理解的原始样子。就是包装了一个新的概念而已,糊弄人的。
根据百度百科的说法:
后期静态绑定的功能,始于PHP5.3开始,用于在继承范围内引用静态调用的类。该功能从语言内部角度考虑被命名为”后期静态绑定“。”后期绑定“的意思是说,static::不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为”静态绑定“,因为它可以用于(但不限于)静态方法的调用。
如果parent::或者self::的method()代码是static::的,则本来被parent或者self缩小的范围,则继续被扩大寻找,到最外层寻找对应的method(),同时考虑继承关系,__CLASS__输出则考虑实际的代码位置。可以理解为类可选范围:缩小=》放大=》缩小的一个过程。【很烧脑】
测试代码一
class S
{
public static function who()
{
echo "__CLASS__:",__CLASS__, PHP_EOL;
}
}
class N extends S
{
public static function who()
{
echo "__CLASS__:",__CLASS__, PHP_EOL;
}
public static function test()
{
static::who(); // N
self::who(); // N => S
N::who(); // N
if(get_parent_class()){
parent::who(); // S => 空
}
else{
echo "\r\n";
}
S::who(); // S
}
}
$n = new N;
$n::test();子类N中覆盖了who方法。所以,static::后期静态绑定的是子类N。
输出值:
__CLASS__:N
__CLASS__:N
__CLASS__:N
__CLASS__:S
__CLASS__:S测试代码二
相同的代码,把test()方法移动到父类里面,如下所示。self::和parent::的运算结果发生了变化。
class S
{
public static function who()
{
echo "__CLASS__:",__CLASS__, PHP_EOL;
}
public static function test()
{
static::who(); // N
self::who(); // N => S
N::who(); // N
if(get_parent_class()){
parent::who(); // S => 空
}
else{
echo "\r\n";
}
S::who(); // S
}
}
class N extends S
{
public static function who()
{
echo "__CLASS__:",__CLASS__, PHP_EOL;
}
}
$n = new N;
$n::test();输出:
__CLASS__:N
__CLASS__:S
__CLASS__:N
__CLASS__:S测试代码三
这里用了三层继承,代码如下:
<?php
class S
{
public static function who()
{
echo "__CLASS__S:",__CLASS__, PHP_EOL;
}
}
class N extends S
{
public static function who()
{
echo "__CLASS__N:",__CLASS__, PHP_EOL;
}
public static function test()
{
static::who(); // X=>N
self::who(); // N
if(get_parent_class()){
parent::who(); // S
}
}
}
class X extends N
{
public static function who()
{
echo "__CLASS__X:",__CLASS__, PHP_EOL;
}
}
class X2 extends N {}
X::test();
X2::test();输出:
__CLASS__X:X
__CLASS__N:N
__CLASS__S:S
__CLASS__N:N
__CLASS__N:N
__CLASS__S:S可见:static::method()是随着调用者是否实际定义method()的变化而变化的。
思考题
下面这个parent::和self::的执行结果,可能和想象的不同。虽然指向不同,但是内部都是static::这个需要考虑后期静态调用的...
class S
{
public static function check()
{
static::who(); // 这个要考虑后期静态绑定
}
public static function who()
{
echo "<S>:", __CLASS__, PHP_EOL;
}
}
class N extends S
{
public static function test()
{
parent::check();
self::check();
}
public static function who()
{
echo "<N>:", __CLASS__, PHP_EOL;
}
}
class X_1 extends N
{
public static function who()
{
echo "<X>:", __CLASS__, PHP_EOL;
}
}
class X_2 extends N { }
X_1::test(); // X_1 X_1
X_2::test(); // N N相关文章
- https://newsn.net/say/php-debug-func.html
- https://newsn.net/say/php-reflect-class.html
- https://baike.baidu.com/item/%E5%90%8E%E6%9C%9F%E9%9D%99%E6%80%81%E7%BB%91%E5%AE%9A/18767291
结束语
static::被称之为后期静态绑定,苏南大叔觉得就是给大家已知的概念加了个新的命名而已。考虑继承关系加方法覆盖关系得到的__CLASS__就是“后期静态绑定”。
更多来自苏南大叔的php经验文章解读,请参考: