Php 如何获取对象';s非限定(短)类名?
如何在PHP名称空间环境中检查对象的类,而不指定完整的名称空间类 例如,假设我有一个对象库/实体/契约/名称 以下代码不起作用,因为get_类返回完整的命名空间类Php 如何获取对象';s非限定(短)类名?,php,class,namespaces,Php,Class,Namespaces,如何在PHP名称空间环境中检查对象的类,而不指定完整的名称空间类 例如,假设我有一个对象库/实体/契约/名称 以下代码不起作用,因为get_类返回完整的命名空间类 If(get_class($object) == 'Name') { ... do this ... } namespace magic关键字返回当前名称空间,如果测试对象具有另一个名称空间,则该名称空间无效 我可以简单地用名称空间指定完整的类名,但这似乎锁定了代码的结构。如果我想动态更改名称空间,也没有多大用处 谁能想出一个有效的
If(get_class($object) == 'Name') {
... do this ...
}
namespace magic关键字返回当前名称空间,如果测试对象具有另一个名称空间,则该名称空间无效
我可以简单地用名称空间指定完整的类名,但这似乎锁定了代码的结构。如果我想动态更改名称空间,也没有多大用处
谁能想出一个有效的方法来做到这一点呢。我想一个选择是正则表达式 在上找到,我在nwhiting.com上发布了它
但是名称空间的概念是构造代码。这也意味着您可以在多个名称空间中使用相同名称的类。因此,理论上,您传递的对象可以具有名称(剥离)类名,同时仍然是一个与您预期完全不同的对象
除此之外,您可能需要检查特定的基类,在这种情况下,
get\u class
根本不起作用。您可能需要检查操作符。您可以使用反射来完成此操作。具体来说,您可以使用该方法,该方法获取类的名称,而不包含其命名空间
首先,您需要构建一个ReflectionClass
实例,然后调用该实例的getShortName
方法:
$reflect = new ReflectionClass($object);
if ($reflect->getShortName() === 'Name') {
// do this
}
然而,我无法想象在许多情况下这是可取的。如果您想要求对象是某个类的成员,测试它的方法是使用。如果您想要一种更灵活的方式来表示某些约束,那么方法就是编写一个接口并要求代码实现该接口。同样,正确的方法是使用instanceof
。(您可以使用ReflectionClass
,但它的性能会差得多。)我使用以下方法:
basename(str_replace('\\', '/', get_class($object)));
下面是PHP5.4的简单解决方案+
namespace {
trait Names {
public static function getNamespace() {
return implode('\\', array_slice(explode('\\', get_called_class()), 0, -1));
}
public static function getBaseClassName() {
return basename(str_replace('\\', '/', get_called_class()));
}
}
}
会有什么回报
namespace x\y\z {
class SomeClass {
use \Names;
}
echo \x\y\z\SomeClass::getNamespace() . PHP_EOL; // x\y\z
echo \x\y\z\SomeClass::getBaseClassName() . PHP_EOL; // SomeClass
}
扩展的类名和命名空间适用于:
namespace d\e\f {
class DifferentClass extends \x\y\z\SomeClass {
}
echo \d\e\f\DifferentClass::getNamespace() . PHP_EOL; // d\e\f
echo \d\e\f\DifferentClass::getBaseClassName() . PHP_EOL; // DifferentClass
}
全局命名空间中的类呢
namespace {
class ClassWithoutNamespace {
use \Names;
}
echo ClassWithoutNamespace::getNamespace() . PHP_EOL; // empty string
echo ClassWithoutNamespace::getBaseClassName() . PHP_EOL; // ClassWithoutNamespace
}
引用php.net:
在Windows上,斜杠(/)和反斜杠()都用作目录分隔符。在其他环境中,它是正斜杠(/)
基于此信息并从arzzzen answer展开,这应适用于Windows和Nix*系统:
<?php
if (basename(str_replace('\\', '/', get_class($object))) == 'Name') {
// ... do this ...
}
在任何环境中都能运行的最快、最简单的解决方案是:
<?php
namespace \My\Awesome\Namespace;
class Foo {
private $shortName;
public function fastShortName() {
if ($this->shortName === null) {
$this->shortName = explode("\\", static::class);
$this->shortName = end($this->shortName);
}
return $this->shortName;
}
public function shortName() {
return basename(strtr(static::class, "\\", "/"));
}
}
echo (new Foo())->shortName(); // "Foo"
?>
将短名称作为一行代码获取(因为):
这是一种干净的方法,并且是。(new\ReflectionClass($obj))->getShortName()代码>是性能方面的最佳解决方案
我很好奇提供的解决方案中哪一个是最快的,所以我做了一个小测试
结果
Reflection: 1.967512512207 s ClassA
Basename: 2.6840535163879 s ClassA
Explode: 2.6507515668869 s ClassA
Reflection: 0.068084406852722 s ClassA
Basename: 0.12301609516144 s ClassA
Explode: 0.14073524475098 s ClassA
Substring: 0.059865570068359 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";
namespace foo\bar\baz;
class ClassA{
public function getClassExplode(){
$c = array_pop(explode('\\', get_class($this)));
return $c;
}
public function getClassReflection(){
$c = (new \ReflectionClass($this))->getShortName();
return $c;
}
public function getClassBasename(){
$c = basename(str_replace('\\', '/', get_class($this)));
return $c;
}
public function getClassSubstring(){
$classNameWithNamespace = get_class($this);
return substr($classNameWithNamespace, strrpos($classNameWithNamespace, '\\')+1);
}
}
$a = new ClassA();
$num = 100000;
$rounds = 10;
$res = array(
"Reflection" => array(),
"Basename" => array(),
"Explode" => array(),
"Substring" => 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);
$start = microtime(true);
for($i = 0; $i < $num; $i++){
$a->getClassSubstring();
}
$end = microtime(true);
$res["Substring"][] = ($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";
echo "Substring: ".array_sum($res["Substring"])/count($res["Substring"])." s ".$a->getClassSubstring()."\n";
名称空间foo\bar\baz;
甲级{
公共函数getClassExplode(){
返回分解('\',static::class)[0];
}
公共函数getClassReflection(){
return(new\ReflectionClass($this))->getShortName();
}
公共函数getClassBasename(){
返回basename(str_replace('\\','/',static::class));
}
}
$a=新类别a();
$num=100000;
$rounds=10;
$res=数组(
“反射”=>array(),
“Basename”=>array(),
“分解”=>array(),
);
对于($r=0;$r<$rounds;$r++){
$start=microtime(真);
对于($i=0;$i<$num;$i++){
$a->getClassReflection();
}
$end=微时间(真);
$res[“反射”][]=($end-$start);
$start=microtime(真);
对于($i=0;$i<$num;$i++){
$a->getClassBasename();
}
$end=微时间(真);
$res[“Basename”][]=($end-$start);
$start=microtime(真);
对于($i=0;$i<$num;$i++){
$a->getClassExplode();
}
$end=微时间(真);
$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”;
结果真让我吃惊。我认为爆炸解决方案将是最快的方法…我在测试中添加了substr
$shortClassName = join('',array_slice(explode('\\', $longClassName), -1));
这是我可以用i5测试的快速测试方法(CentOS PHP5.3.3,Ubuntu PHP5.5.9)
$classNameWithNamespace=get_class($this);
return substr($classNameWithNamespace, strrpos($classNameWithNamespace, '\\')+1);
结果
Reflection: 1.967512512207 s ClassA
Basename: 2.6840535163879 s ClassA
Explode: 2.6507515668869 s ClassA
Reflection: 0.068084406852722 s ClassA
Basename: 0.12301609516144 s ClassA
Explode: 0.14073524475098 s ClassA
Substring: 0.059865570068359 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";
namespace foo\bar\baz;
class ClassA{
public function getClassExplode(){
$c = array_pop(explode('\\', get_class($this)));
return $c;
}
public function getClassReflection(){
$c = (new \ReflectionClass($this))->getShortName();
return $c;
}
public function getClassBasename(){
$c = basename(str_replace('\\', '/', get_class($this)));
return $c;
}
public function getClassSubstring(){
$classNameWithNamespace = get_class($this);
return substr($classNameWithNamespace, strrpos($classNameWithNamespace, '\\')+1);
}
}
$a = new ClassA();
$num = 100000;
$rounds = 10;
$res = array(
"Reflection" => array(),
"Basename" => array(),
"Explode" => array(),
"Substring" => 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);
$start = microtime(true);
for($i = 0; $i < $num; $i++){
$a->getClassSubstring();
}
$end = microtime(true);
$res["Substring"][] = ($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";
echo "Substring: ".array_sum($res["Substring"])/count($res["Substring"])." s ".$a->getClassSubstring()."\n";
以下是使用“SubstringStrChr”更新的测试结果(最多可保存约0.001秒):
当类没有命名空间时,可能会得到意外的结果。也就是说,get\u class
返回Foo
,那么$baseClass
将是oo
$baseClass = substr(strrchr(get_class($this), '\\'), 1);
这可以通过在get\u class
前面加反斜杠轻松解决:
$baseClass = substr(strrchr('\\'.get_class($this), '\\'), 1);
现在,没有名称空间的类也将返回正确的值。根据@MaBi的回答,我做了以下几点:
trait ClassShortNameTrait
{
public static function getClassShortName()
{
if ($pos = strrchr(static::class, '\\')) {
return substr($pos, 1);
} else {
return static::class;
}
}
}
您可以这样使用:
namespace Foo\Bar\Baz;
class A
{
use ClassShortNameTrait;
}
A::class
返回Foo\Bar\Baz\A
,但A::getClassShortName()
返回A
适用于PHP>=5.5。如果需要知道从类内部调用的类名,并且不需要名称空间,可以使用此名称空间
$calledClass = get_called_class();
$name = strpos($calledClass, '\\') === false ?
$calledClass : substr($calledClass, strrpos($calledClass, '\\') + 1);
当你在一个类中有一个被其他类扩展的方法时,这是非常好的。此外,如果根本不使用名称空间,这也可以工作
例如:
<?php
namespace One\Two {
class foo
{
public function foo()
{
$calledClass = get_called_class();
$name = strpos($calledClass, '\\') === false ?
$calledClass : substr($calledClass, strrpos($calledClass, '\\') + 1);
var_dump($name);
}
}
}
namespace Three {
class bar extends \One\Two\foo
{
public function bar()
{
$this->foo();
}
}
}
namespace {
(new One\Two\foo)->foo();
(new Three\bar)->bar();
}
// test.php:11:string 'foo' (length=3)
// test.php:11:string 'bar' (length=3)
如果您使用的是Laravel PHP框架,那么这里有一种更简单的方法:
<?php
// usage anywhere
// returns HelloWorld
$name = class_basename('Path\To\YourClass\HelloWorld');
// usage inside a class
// returns HelloWorld
$name = class_basename(__CLASS__);
/**
* Get the class "basename" of the given object / class.
*
* @param string|object $class
* @return string
*/
function class_basename($class)
{
$class = is_object($class) ? get_class($class) : $class;
return basename(str_replace('\\', '/', $class));
}
我发现自己处于一种独特的情况下,instanceof
无法使用(特别是名称空间的traits),我需要以最有效的方式使用短名称,因此我对我的
$bench = new \xori\Benchmark(1000, 1000); # https://github.com/Xorifelse/php-benchmark-closure
$shell = new \my\fancy\namespace\classname(); # Just an empty class named `classname` defined in the `\my\fancy\namespace\` namespace
$bench->register('strrpos', (function(){
return substr(static::class, strrpos(static::class, '\\') + 1);
})->bindTo($shell));
$bench->register('safe strrpos', (function(){
return substr(static::class, ($p = strrpos(static::class, '\\')) !== false ? $p + 1 : 0);
})->bindTo($shell));
$bench->register('strrchr', (function(){
return substr(strrchr(static::class, '\\'), 1);
})->bindTo($shell));
$bench->register('reflection', (function(){
return (new \ReflectionClass($this))->getShortName();
})->bindTo($shell));
$bench->register('reflection 2', (function($obj){
return $obj->getShortName();
})->bindTo($shell), new \ReflectionClass($shell));
$bench->register('basename', (function(){
return basename(str_replace('\\', '/', static::class));
})->bindTo($shell));
$bench->register('explode', (function(){
$e = explode("\\", static::class);
return end($e);
})->bindTo($shell));
$bench->register('slice', (function(){
return join('',array_slice(explode('\\', static::class), -1));
})->bindTo($shell));
print_r($bench->start());
+-----------------+--------+
| registered name | speed |
+-----------------+--------+
| reflection 2 | 70.75% |
| strrpos | 60.38% |
| safe strrpos | 57.69% |
| strrchr | 54.88% |
| explode | 46.60% |
| slice | 37.02% |
| reflection | 16.75% |
| basename | 0.00% |
+-----------------+--------+
$base_class = preg_replace('/^([\w\\\\]+\\\\)?([^\\\\]+)$/', '$2', get_class($myobject));
\yii\helpers\StringHelper::basename(get_class($model));
// both of the below calls will output: ShortClassName
echo preg_replace('/.*\\\\/', '', 'ShortClassName');
echo preg_replace('/.*\\\\/', '', 'SomeNamespace\SomePath\ShortClassName');
namespace Foo\Bar\Baz;
class Test {
public function getClass() {
return str_replace(__NAMESPACE__.'\\', '', static::class);
}
}
if(class_basename(get_class($object)) == 'Name') {
... do this ...
}
if(class_basename(ClassName::class) == 'ClassName') {
... do this ...
}
preg_replace('/^(\w+\\\)*/', '', static::class)