如何获取对象的不限定(短)类名?

2022-08-30 06:27:38

如何在不指定完整命名空间类的情况下检查 PHP 名称间隔环境中对象的类。

例如,假设我有一个对象库/实体/合同/名称。

下面的代码不起作用,get_class返回完整的命名空间类。

If(get_class($object) == 'Name') {
... do this ...
}

命名空间 magic 关键字返回当前命名空间,如果测试对象具有另一个命名空间,则没有用。

我可以简单地使用命名空间指定完整的类名,但这似乎锁定了代码的结构。如果我想动态更改命名空间,也没有多大用处。

任何人都可以想到一种有效的方法来做到这一点。我想一个选项是正则表达式。


答案 1

您可以通过反射来执行此操作。具体来说,可以使用 ReflectionClass::getShortName 方法,该方法获取不带命名空间的类的名称。

首先,您需要构建一个实例,然后调用该实例的方法:ReflectionClassgetShortName

$reflect = new ReflectionClass($object);
if ($reflect->getShortName() === 'Name') {
    // do this
}

但是,我无法想象在很多情况下这是可取的。如果要要求对象是某个类的成员,则使用 instanceof 来测试它。如果你想要一种更灵活的方法来发出某些约束的信号,那么做到这一点的方法是编写一个接口,并要求代码实现该接口。同样,执行此操作的正确方法是使用 。(您可以使用 来执行此操作,但它的性能会差得多。instanceofReflectionClass


答案 2

(new \ReflectionClass($obj))->getShortName();是性能方面的最佳解决方案。

我很好奇提供的解决方案中哪一个是最快的,所以我做了一个小测试。

结果

Reflection: 1.967512512207 s ClassA
Basename:   2.6840535163879 s ClassA
Explode:    2.6507515668869 s ClassA

法典

namespace foo\bar\baz;

class ClassA{
    public function getClassExplode(){
        return explode('\\', static::class)[0];
    }

    public function getClassReflection(){
        return (new \ReflectionClass($this))->getShortName();
    }

    public function getClassBasename(){
        return basename(str_replace('\\', '/', static::class));
    }
}

$a = new ClassA();
$num = 100000;

$rounds = 10;
$res = array(
    "Reflection" => array(),
    "Basename" => array(),
    "Explode" => array(),
);

for($r = 0; $r < $rounds; $r++){

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassReflection();
    }
    $end = microtime(true);
    $res["Reflection"][] = ($end-$start);

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassBasename();
    }
    $end = microtime(true);
    $res["Basename"][] = ($end-$start);

    $start = microtime(true);
    for($i = 0; $i < $num; $i++){
        $a->getClassExplode();
    }
    $end = microtime(true);
    $res["Explode"][] = ($end-$start);
}

echo "Reflection: ".array_sum($res["Reflection"])/count($res["Reflection"])." s ".$a->getClassReflection()."\n";
echo "Basename: ".array_sum($res["Basename"])/count($res["Basename"])." s ".$a->getClassBasename()."\n";
echo "Explode: ".array_sum($res["Explode"])/count($res["Explode"])." s ".$a->getClassExplode()."\n";

结果实际上让我感到惊讶。我认为爆炸解决方案将是最快的方法...


推荐