[php] 객체의 정규화되지 않은 (짧은) 클래스 이름을 어떻게 얻습니까?
전체 네임 스페이스 클래스를 지정하지 않고 PHP 네임 스페이스 환경 내에서 오브젝트 클래스를 확인하는 방법
예를 들어 객체 라이브러리 / 엔티티 / 계약 / 이름이 있다고 가정합니다.
get_class가 전체 네임 스페이스 클래스를 리턴하므로 다음 코드는 작동하지 않습니다.
If(get_class($object) == 'Name') {
... do this ...
}
네임 스페이스 magic 키워드는 현재 네임 스페이스를 반환하며, 테스트 된 객체에 다른 네임 스페이스가 있으면 사용되지 않습니다.
네임 스페이스로 전체 클래스 이름을 간단히 지정할 수는 있지만 코드 구조에 잠겨있는 것 같습니다. 네임 스페이스를 동적으로 변경하려는 경우에도 많이 사용되지 않습니다.
누구나 효율적인 작업 방법을 생각할 수 있습니까? 하나의 옵션이 정규식이라고 생각합니다.
답변
리플렉션으로이 작업을 수행 할 수 있습니다. 특히 ReflectionClass::getShortName
네임 스페이스없이 클래스 이름을 가져 오는 메서드 를 사용할 수 있습니다 .
먼저 ReflectionClass
인스턴스 를 빌드 한 다음 getShortName
해당 인스턴스 의 메소드 를 호출 해야합니다.
$reflect = new ReflectionClass($object);
if ($reflect->getShortName() === 'Name') {
// do this
}
그러나 이것이 바람직한 많은 상황을 상상할 수 없습니다. 객체가 특정 클래스의 멤버인지 확인하려면 테스트 방법을 사용하십시오 instanceof
. 특정 제약 조건을 신호하는보다 유연한 방법을 원한다면 인터페이스를 작성하고 코드가 해당 인터페이스를 구현해야합니다. 이 작업을 수행하는 올바른 방법은입니다 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 의 테스트에 substr을 추가
했으며 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";
== 업데이트 ==
@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__);
답변
나는 이것을 사용한다 :
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'
Linux와 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% |
+-----------------+--------+