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
经验文章解读,请参考:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。