source

개체의 정규화되지 않은(짧은) 클래스 이름을 가져오려면 어떻게 해야 합니까?

manysource 2023. 1. 17. 21:21

개체의 정규화되지 않은(짧은) 클래스 이름을 가져오려면 어떻게 해야 합니까?

풀 네임슬래드 클래스를 지정하지 않고 PHP 네임 스페이스 환경 내의 오브젝트 클래스를 체크하려면 어떻게 해야 합니까?

예를 들어 오브젝트 라이브러리/엔티티/계약/이름 등이 있다고 가정합니다.

다음 코드는 get_class가 풀 네임슬레이드 클래스를 반환하기 때문에 작동하지 않습니다.

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

namespace magic 키워드는 현재 네임스페이스를 반환합니다.테스트된 개체에 다른 네임스페이스가 있는 경우에는 사용할 수 없습니다.

단순히 네임스페이스로 풀 클래스 이름을 지정할 수 있지만, 이것은 코드 구조에 잠겨 있는 것 같습니다.또한 네임스페이스를 동적으로 변경할 경우 큰 도움이 되지 않습니다.

이것을 효율적으로 할 수 있는 방법을 생각해 낼 수 있는 사람은 누구입니까?한 가지 방법은 regex인 것 같아요.

반성을 해서 할 수 있어요.구체적으로는 네임스페이스 없이 클래스 이름을 가져오는 메서드를 사용할 수 있습니다.

VIP, VIP를 만들어야 .ReflectionClass합니다.getShortName: "Method" "Method" :

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

하지만 이것이 바람직한 상황은 상상할 수 없습니다.오브젝트가 특정 클래스의 멤버여야 하는 경우 테스트 방법은 를 사용하는 것입니다.특정 제약조건을 보다 유연하게 시그널링할 경우에는 인터페이스를 기술하고 그 인터페이스를 코드로 구현하도록 요구합니다.다시 말씀드리지만 올바른 방법은instanceof (와 할 수 .)ReflectionClass하지만 퍼포먼스는 훨씬 나빠집니다.)

(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";

그 결과는 사실 나를 놀라게 했다.폭발물이 가장 빠른 방법인 줄 알았는데...

https://stackoverflow.com/a/25472778/2386943의 테스트에 기판을 추가했습니다.그것이 바로 i5를 사용한 테스트(CentOS PHP 5.3.3, Ubuntu PHP 5.5.9)의 고속 방법입니다.

$classNameWithNamespace=get_class($this);
return substr($classNameWithNamespace, strrpos($classNameWithNamespace, '\\')+1);

결과.

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(){
    $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";

==UPDATE==

@MrBandersnatch의 코멘트에서 설명한 바와 같이 이를 위한 더 빠른 방법이 있습니다.

return substr(strrchr(get_class($this), '\\'), 1);

다음은 "SubstringStrChr"(최대 0.001초 절약)을 사용한 업데이트된 테스트 결과입니다.

Reflection: 0.073065280914307 s ClassA
Basename: 0.12585079669952 s ClassA
Explode: 0.14593172073364 s ClassA
Substring: 0.060415267944336 s ClassA
SubstringStrChr: 0.059880912303925 s ClassA

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));
}

나는 이것을 사용한다.

basename(str_replace('\\', '/', get_class($object)));

짧은 이름을 원라이너로 얻으려면(PHP 5.4 이후)

echo (new ReflectionClass($obj))->getShortName();

그것은 깔끔한 접근이고 합리적이다.

는 내가 에 처해 것을 .instanceof(특정 이름순 특성)은 사용할 수 없습니다.또한 가장 효율적인 방법으로 짧은 이름이 필요했기 때문에 저만의 벤치마크를 조금 해봤습니다.여기에는 이 질문에 대한 답변과 다른 모든 방법 및 변형이 포함되어 있습니다.

$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());

전체 결과 목록은 여기에 나와 있지만, 주요 내용은 다음과 같습니다.

  • 어차피 반사를 할 거면 반사를 해서$obj->getShortName()는 가장 빠른 방법입니다.단, 짧은 이름을 얻기 위해서만 리플렉션을 사용하는 것이 거의 가장 느린 방법입니다.
  • 'strrpos' 경우 할 수 그 때문에, 「네임스페이스」는 「네임스페이스」에 없습니다.'safe strrpos'조금 느리긴 하지만 이게 승자라고 할 수 있을 것 같아요.
  • ★★★★★★★★★★★★★★★★★를 만들다'basename' 와 의 호환성에 는, windows Windows 를 사용할 .str_replace()★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

단순화된 결과 표에서는 속도가 가장 느린 방법과 비교하여 측정됩니다.

+-----------------+--------+
| 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%  |
+-----------------+--------+

하시면 됩니다.explode와 '네임스페이스'를 하기 위해end클래스 이름을 가져옵니다.

$ex = explode("\\", get_class($object));
$className = end($ex);

Yii 웨이

\yii\helpers\StringHelper::basename(get_class($model));

Yii는 Gii 코드 생성기에서 이 메서드를 사용합니다.

방법 문서

이 메서드는 php 함수 basename()과 비슷하지만 \과 / 둘 다 운영체제로부터 독립된 디렉토리 구분자로 취급됩니다.이 메서드는 주로 php 네임스페이스에서 동작하도록 작성되었습니다.실제 파일 경로로 작업할 경우 php의 basename()이 제대로 작동합니다.주의: 이 메서드는 실제 파일 시스템 또는 ".."와 같은 경로 구성 요소를 인식하지 않습니다.

상세 정보:

https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseStringHelper.php http://www.yiiframework.com/doc-2.0/yii-helpers-basestringhelper.html#basename()-detail

여기 PHP 5.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
}

오래된 투고인 것은 알지만, 이것이 내가 사용하는 것입니다.상기 투고보다 빨리, 이 메서드를 당신의 클래스에서 호출해 주세요.Reflection을 사용하는 것보다 훨씬 빠릅니다.

namespace Foo\Bar\Baz;

class Test {
    public function getClass() {
        return str_replace(__NAMESPACE__.'\\', '', static::class);
    }
}

클래스 내부에서 호출된 클래스 이름을 알고 네임스페이스를 원하지 않는 경우 이 이름을 사용할 수 있습니다.

$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)

i스에 i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i. ,get_classFoo , , , 「 」$baseClassoo.

$baseClass = substr(strrchr(get_class($this), '\\'), 1);

는 접두사를 쉽게 할 수 .get_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::classFoo\Bar\Baz\AA::getClassShortName()A.

PHP > = 5.5에서 작동합니다.

오래된 regex가 앞에서 설명한 대부분의 방법보다 빠른 것 같습니다.

// both of the below calls will output: ShortClassName

echo preg_replace('/.*\\\\/', '', 'ShortClassName');
echo preg_replace('/.*\\\\/', '', 'SomeNamespace\SomePath\ShortClassName');

따라서 이것은 짧은 클래스 이름 또는 정규화된(표준) 클래스 이름을 제공해도 작동합니다.

regex는 마지막 구분자를 찾을 때까지 이전의 모든 문자를 소비합니다(이것도 소비됩니다).나머지 문자열은 짧은 클래스 이름이 됩니다.

다른 구분 기호(예: / )를 사용하려면 대신 해당 구분 기호를 사용하십시오.백슬래시(즉, 백슬래시)를 피하는 것을 잊지 마십시오.\) 및 입력 패턴의 패턴 문자(즉, /)도 지정합니다.

get_class의 문서 페이지에서 찾을 수 있습니다.여기서는 nwhiting dot com에서 제가 게시한 것입니다.

function get_class_name($object = null)
{
    if (!is_object($object) && !is_string($object)) {
        return false;
    }

    $class = explode('\\', (is_string($object) ? $object : get_class($object)));
    return $class[count($class) - 1];
}

하지만 네임스페이스의 개념은 코드를 구성하는 것입니다.즉, 여러 네임스페이스에 같은 이름의 클래스를 둘 수 있습니다.따라서 이론적으로 전달되는 객체는 이름(스트라이핑된) 클래스 이름을 가지면서도 예상과는 전혀 다른 객체일 수 있습니다.

그 외에도 특정 기본 클래스를 확인하는 것이 좋습니다.이 경우get_class전혀 효과가 없습니다.오퍼레이터를 체크하는 것이 좋습니다.

여기 있습니다.

public function get_name()
{
   return str_replace(__NAMESPACE__ . '\\', '', __CLASS__);
}

php.net의 견적:

Windows 에서는, 슬래시(/)와 백슬래시()가 모두 디렉토리 구분 문자로 사용됩니다.다른 환경에서는 포워드 슬래시(/)입니다.

이 정보에 근거해, arzzen으로부터의 확장에 근거해, Windows*시스템과 Nix*시스템 양쪽에서 유효하게 됩니다.

<?php

if (basename(str_replace('\\', '/', get_class($object))) == 'Name') {
    // ... do this ...
}

주의: 저는 다음과 같은 벤치마크를 실시했습니다.ReflectionClass 반대하여basename+str_replace+get_class이 기본 보다 약 YMMV는 20%입니다.

모든 환경에서 작동하는 가장 빠르고 쉬운 솔루션은 다음과 같습니다.

<?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"

?>
$shortClassName = join('',array_slice(explode('\\', $longClassName), -1));

네임스페이스(또는 '\'가 없는 경우 이름)를 사용하여 클래스 이름에서 마지막 \ 뒤에 원하는 것이 있으면 다음과 같은 작업을 수행할 수 있습니다.

$base_class = preg_replace('/^([\w\\\\]+\\\\)?([^\\\\]+)$/', '$2', get_class($myobject));

기본적으로는 문자 또는 백슬래시의 임의의 조합을 가져오고 마지막 백슬래시까지는 백슬래시가 아닌 문자만 위로, 문자열이 끝날 때까지 되돌리는 것이 regex입니다.첫 번째 그룹 뒤에 ?를 추가하면 패턴 일치가 존재하지 않으면 문자열 전체가 반환됩니다.

"Reflection Class"는 버전에 따라 달라질 수 있으므로 다음을 사용하십시오.

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

또는 클리어

if(class_basename(ClassName::class) == 'ClassName') {
... do this ...
}

여기서 찾은 가장 빠른 시간PHP 7.2Ububntu 18.04

preg_replace('/^(\w+\\\)*/', '', static::class)

모든 벤치마크에서 PHP 8.1.6을 탑재한 Mac에서 가장 빠르게 실행되는 작은 기능만 있습니다.이 함수는 제공된 문자열이 비어 있거나 네임스페이스가 없는 경우(포함되지 않음) 상황을 처리합니다.\문자 입력)을 클릭합니다.

<?php

declare(strict_types=1);

use function strrpos;
use function substr;

class Utils {
    /** @param class-string $class */
    public static function classShortName(string $class): string
    {
        $pos = strrpos($class, '\\');

        if ($pos === false) {
            return $class;
        }

        return substr($class, $pos + 1);
    }
}

또는 '네임스페이스가 없는 )\

Reflection: 0.0082374811172485 s ClassA
Basename: 0.0071691036224365 s ClassA
Explode: 0.0077154636383057 s ClassA
Substring: 0.0076151371002197 s lassA // Doesn't work correctly
PregReplace: 0.0064111948013306 s lassA // Doesn't work correctly
Utils::classShortName: 0.0043857336044312 s ClassA

벤치마크(전체 네임스페이스):

Reflection: 0.0093500852584839 s ClassA
Basename: 0.012896633148193 s ClassA
Explode: 0.013392925262451 s ClassA
Substring: 0.0083461999893188 s ClassA // almost same function runs slower ?!
PregReplace: 0.011274862289429 s ClassA
Utils::classShortName: 0.0075617074966431 s ClassA

언급URL : https://stackoverflow.com/questions/19901850/how-do-i-get-an-objects-unqualified-short-class-name