静态方法中的static::class和get_called_class()有什么区别?__CLASS__、get_class()和self::class又有什么区别?(这是一个提问标题)

21
我看过几个关于如何在PHP中获取类或对象名称的讨论帖。然而,我无法看到解释不同可能性之间区别的任何地方。我希望这里有人能帮助我。
因此,为了获取所调用类的类名,我知道两种可能性:
1. `get_called_class()` 2. `static::class`
(对于非静态类,使用`get_class($this)`)
而要获取代码所在类的类名,我知道以下三种可能性:
1. `get_class()` 2. `__CLASS__` 3. `self::class`
我是否忽略了任何差异?一个方法比另一个方法更具优势和劣势是什么?

尝试在一个类中和继承它的类中,实例方法和静态方法中使用所有这些方法来找出答案。 - axiac
这就是我所做的,它们都返回相同的结果。我认为可能有一些其他的差异我想不到。毕竟,为什么在PHP 5.5中引入::class,当你可以使用get_class()__CLASS__get_called_class()来完成同样的事情呢? - Alexander Jank
::class 可以在编译时评估,get_class() 是一个函数调用,因此它返回的值仅在执行时可用。 - axiac
这是否意味着 ::class 更高效? - Alexander Jank
差别微不足道。如果你的目标是优化,那么请检查对数据库(优化 SQL 查询并减少查询次数和检索数据的量)、文件系统和远程资源的访问。 - axiac
@AlexanderJank:基本上,::class 被添加用于获取任何类的 FQN,只需使用本地类名(没有对象,并且从类外部);它可以像 get_class()get_called_class()__CLASS__ 一样工作,这只是一个连锁反应。请参阅 "Class Name Resolution As Scalar Via "class" Keyword" PHP RFC。 - outis
2个回答

19

三种获取类名的方法之间的区别

get_class()

返回一个对象所属类的名称,包括命名空间。

如果没有参数,get_class() 返回当前类(不是实例)的名称,如果有参数,则返回指定对象实例的类名称(包括其命名空间),并将该对象实例作为第一个且唯一的参数传递。

__CLASS__

这是一个魔术常量,返回当前类的名称和命名空间。但无法用于测试其他对象的类名。 自 PHP 5.4 以来,它可以在 trait 中使用。也就是说,当 trait 用于一个类中时,它将返回该类的命名空间和名称。

::class

仅自 PHP 5.5 版本后提供。它使用类名和命名空间解析来获取信息,因此不需要先实例化该类。还请注意:

使用 ::class 进行类名解析是编译时转换。这意味着在创建类名字符串时还没有发生自动加载。因此,即使类不存在,也会扩展类名。在这种情况下不会引发错误。

测试

<?php
namespace nTest;
trait tTest {
  function __toString() {return get_class();}
  function className() {return __CLASS__;}  // per PHP 5.4
  function traitName() {return __TRAIT__;}
}
class cTest {
  use tTest;
  function usedTraitName() {return __TRAIT__;}
}
class cClassWithoutObject {}
$oTest = new cTest;

header('Content-type: text/plain');
print                                  // Output:
    $oTest . PHP_EOL                   // 'nTest::cTest'
  . get_class($oTest) . PHP_EOL        // 'nTest::cTest'
  . $oTest->className() . PHP_EOL      // 'nTest::cTest'
  . $oTest->traitName() . PHP_EOL      // 'nTest::tTest' (trait!)
  . $oTest->usedTraitName() . PHP_EOL  // '' (no trait!)
  . cTest::class . PHP_EOL             // 'nTest::cTest'
  . cClassWithoutObject::class;        // 'nTest::cTestNotInstantiated'

2
我爱你的回答。解除了我好奇心的负担! - D. Petrov

7

__CLASS__get_class($this) 之间的一个重要差异是,在使用继承时,__CLASS__ 将给出包含该代码的类的名称(可能是父类),而 get_class($this) 将在运行时给出 $this 的具体类名。

示例:

class Animal {

    function printCompileTimeType() {

        echo __CLASS__;
    }

    function printOverridableCompileTimeType() {

        echo __CLASS__;
    }

    function printType() {

        echo get_class($this);
    }
}

class Dog extends Animal {

    function printOverridableCompileTimeType() {

        echo __CLASS__;
    }
}

$animal = new Animal();
$dog = new Dog();

$animal->printCompileTimeType(); // Prints 'Animal'.
$animal->printOverridableCompileTimeType(); // Prints 'Animal'.
$animal->printType(); // Prints 'Animal'.

$dog->printCompileTimeType(); // Prints 'Animal'.
$dog->printOverridableCompileTimeType(); // Prints 'Dog'.
$dog->printType(); // Prints 'Dog'.

我认为get_class($this)通常更有用,因为它可以在任何地方预测性地工作,而不需要编写重复的覆盖代码,如printOverridableCompileTimeType


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接