Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何获取对象';s非限定(短)类名?_Php_Class_Namespaces - Fatal编程技术网

Php 如何获取对象';s非限定(短)类名?

Php 如何获取对象';s非限定(短)类名?,php,class,namespaces,Php,Class,Namespaces,如何在PHP名称空间环境中检查对象的类,而不指定完整的名称空间类 例如,假设我有一个对象库/实体/契约/名称 以下代码不起作用,因为get_类返回完整的命名空间类 If(get_class($object) == 'Name') { ... do this ... } namespace magic关键字返回当前名称空间,如果测试对象具有另一个名称空间,则该名称空间无效 我可以简单地用名称空间指定完整的类名,但这似乎锁定了代码的结构。如果我想动态更改名称空间,也没有多大用处 谁能想出一个有效的

如何在PHP名称空间环境中检查对象的类,而不指定完整的名称空间类

例如,假设我有一个对象库/实体/契约/名称

以下代码不起作用,因为get_类返回完整的命名空间类

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)