我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本文讨论在类方法里面确定当前类的方案途径,在自定义class的时候,可以方便的确定当前代码的身份。主要的方法是常量__CLASS__和函数get_class(),同时和函数get_called_class()做对比。

苏南大叔:php教程,如何在方法中代码判断归属于哪个class类? - php判断类归属
php教程,如何在方法中代码判断归属于哪个class类?(图2-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程经验文章。测试环境:win10nginx@1.15.11php@8.2.10-nts

当前类:__CLASS__ / get_class()

__CLASS__的结果,恒等于get_class()的结果,指的是当前的代码所在的实际的类。

也就是说:

  • 如果当前代码实际在子类里面,则判断结果为子类。
  • 如果在父类里面,即使方法被继承了,依然返回父类。

参考文档:

调用类:get_called_class()

get_called_class()返回的是类方法的调用者是谁,主要用于类继承的情况。官方的说法是:获得后期静态绑定("Late Static Binding")类的名称。

  • get_called_class()可能等于__CLASS__或者get_class(),则可能所有代码都在子类里面。
  • get_called_class()可能不等于__CLASS__或者get_class(),那么代码大概率是在父类里面。

参考文档:

父类:get_parent_class()

get_parent_class()获得对象或者类的父类名字,它可以脱离类方法独立调用。没有父类的话,就显示为空(实际是个bool(false)),并不显示自身。

测试代码一,最简单常见的情况

class S
{
    public function test()
    {
        echo "from S", PHP_EOL;
        echo "__CLASS__:",__CLASS__, PHP_EOL;
        echo "get_class():",get_class(), PHP_EOL;
        echo "get_called_class():",get_called_class(), PHP_EOL;
        echo "get_parent_class():",get_parent_class(), PHP_EOL;
        echo PHP_EOL;
    }
}
$s = new S();
$s->test();

输出:

from S
__CLASS__:S
get_class():S
get_called_class():S
get_parent_class():

测试代码二,类继承

// ...
class N1 extends S
{
}
class N2 extends S
{
    public function test()
    {
        echo "from N2", PHP_EOL;
        echo "__CLASS__:",__CLASS__, PHP_EOL;
        echo "get_class():",get_class(), PHP_EOL;
        echo "get_called_class():",get_called_class(), PHP_EOL;
        echo "get_parent_class():",get_parent_class(), PHP_EOL;
        echo PHP_EOL;
    }
}
$n1 = new N1();
$n1->test();

$n2 = new N2();
$n2->test();

输出:

from S
__CLASS__:S
get_class():S
get_called_class():N1
get_parent_class():

from N2
__CLASS__:N2
get_class():N2
get_called_class():N2
get_parent_class():S

在这个例子里面,

  • N1继承了判断代码所在的方法,但是__CLASS__get_class()诚实的反馈代码真实所在位置。
  • N2同样继承了对应方法,但是在其内部进行了改写,所以__CLASS__get_class()的结果,暂时等于get_called_class()的结果。但是,与get_parent_class()的结果,并不相同。

测试代码三,使用trait

把公有的测试代码提取出来做一个trait,看看结果会如何?

trait ssnn{
    public function test()
    {
        echo "from ssnn", PHP_EOL;
        echo "__CLASS__:",__CLASS__, PHP_EOL;
        echo "get_class():",get_class(), PHP_EOL;
        echo "get_called_class():",get_called_class(), PHP_EOL;
        echo "get_parent_class():",get_parent_class(), PHP_EOL;
        echo PHP_EOL;
    }
}
class S
{
    use ssnn;
}
class N1 extends S
{
}
class N2 extends S
{
    use ssnn;
}
$s = new S();
$s->test();

$n1 = new N1();
$n1->test();

$n2 = new N2();
$n2->test();

结果输出:

from ssnn
__CLASS__:S
get_class():S
get_called_class():S
get_parent_class():

from ssnn
__CLASS__:S
get_class():S
get_called_class():N1
get_parent_class():

from ssnn
__CLASS__:N2
get_class():N2
get_called_class():N2
get_parent_class():S

从输出结果上来看,trait代码很中立,吃谁的饭就替谁说话。和已知的测试结果一致,并不影响结果走向。

苏南大叔:php教程,如何在方法中代码判断归属于哪个class类? - get_class范例代码
php教程,如何在方法中代码判断归属于哪个class类?(图2-2)

特例一

如果类存在于命名空间中,则测试代码的结果会带上命名空间的路径信息。

namespace SN;
//...

输出:

from ssnn
__CLASS__:SN\S
get_class():SN\S
get_called_class():SN\S
get_parent_class():

from ssnn
__CLASS__:SN\S
get_class():SN\S
get_called_class():SN\N1
get_parent_class():

from ssnn
__CLASS__:SN\N2
get_class():SN\N2
get_called_class():SN\N2
get_parent_class():SN\S

特例二

不在上下文中隐式获得被判断的类对象,而是直接调用:

$s = new S();
$n1 = new N1();
$n2 = new N2();
echo get_class($s),PHP_EOL;   // S
echo get_class($n1),PHP_EOL;  // N1
echo get_class($n2),PHP_EOL;  // N2
// echo get_called_class($s);
// echo get_called_class($n1);
// echo get_called_class($n2);
echo get_parent_class($s),PHP_EOL; // 空
echo get_parent_class($n1),PHP_EOL; // S
echo get_parent_class($n2),PHP_EOL; // S

这里可以看到区别:

  • get_class(),这个时候就变乖了,不在根据代码实际在哪个类里面做判断了。
  • get_called_class(),直接报错,不能这么用。
  • get_parent_class(),也变乖了,结果也不根据代码实际位置变化了。

思考题

根据本文的结论,看看下面的代码的运算结果是啥:

class S
{
    public function test()
    {
        var_dump(__CLASS__);
        var_dump(get_class());
        var_dump(get_called_class());
        var_dump(get_parent_class());
    }
}
class N extends S
{
    public function _test()
    {
        $this->test();
    }
}
class NN extends N { }
$nn = new NN();
$nn->_test();   

答案是:

newsn.net:这里是【评论】可见内容

相关链接

结束语

如果把相关测试代码放在方法里面,让它自己判断参数的话,可能由于代码位置的不同,产生和预期值不符的结果。同时,苏南大叔有个猜想,php里面的这个继承,并不是说让子类拥有了对应的方法,而是让子类拥有了指挥父类对应的方法的能力。(细品...)

更多苏南大叔的php经验文章,请点击:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   php