How do I get an object's unqualified (short) class name?
Asked Answered
B

24

203

How do I check the class of an object within the PHP name spaced environment without specifying the full namespaced class.

For example suppose I had an object library/Entity/Contract/Name.

The following code does not work as get_class returns the full namespaced class.

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

The namespace magic keyword returns the current namespace, which is no use if the tested object has another namespace.

I could simply specify the full classname with namespaces, but this seems to lock in the structure of the code. Also not of much use if I wanted to change the namespace dynamically.

Can anyone think of an efficient way to do this. I guess one option is regex.

Baillieu answered 11/11, 2013 at 8:28 Comment(3)
It seems near pointless because different namespaces could have same class names defined inside them, so how will you handle that? And that is because full qualified class name is returned in your samplePernell
I'm on a mobile device, so I can't submit a decent answer, but the solution is reflection, specifically ReflectionClass::getShortName - php.net/manual/en/reflectionclass.getshortname.phpSecretary
For people looking for a reason to want this: it might be useful in a helper function in a common base class (i.e. multiple namespaces is never an issue in this situation).Dynamic
S
246

You can do this with reflection. Specifically, you can use the ReflectionClass::getShortName method, which gets the name of the class without its namespace.

First, you need to build a ReflectionClass instance, and then call the getShortName method of that instance:

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

However, I can't imagine many circumstances where this would be desirable. If you want to require that the object is a member of a certain class, the way to test it is with instanceof. If you want a more flexible way to signal certain constraints, the way to do that is to write an interface and require that the code implement that interface. Again, the correct way to do this is with instanceof. (You can do it with ReflectionClass, but it would have much worse performance.)

Secretary answered 11/11, 2013 at 15:9 Comment(17)
instanceof is exactly what I am looking for, but I get a strange result on one hierarchy. I enter echo get_class($tenant) and get Library\Entity\People\Tenant. Then enter var_dump($tenant instanceof Tenant) and get Bool(false) - any thoughts? Maybe I need to log as a separate question.Baillieu
@Baillieu Because Tenant doesn't exist in the current namespace. Try var_dump($tenant instanceof \Library\Entity\People\Tenant) instead. Also, investigate how to use the use operator, and the general concept behind PHP namespaces!Secretary
I had to add a slash in front like this $reflect = new \ReflectionClass($object);Clemens
I generally don't like to do a lot of ReflectionClass voodoo in my application because it can lead to unexpected results if mis-used (protected methods becoming public, etc.). You can use simple string replacement on PHP magic constants instead: str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. It's also much faster, performance-wise.Miltiades
@FranklinPStrube Unless I'm missing something, that gets the short name of the current class, rather than the class of the object. I agree that use of reflection usually means you're Doing It Wrong.Secretary
Thanks !! I've only required this once. My enumeration clases are using language files for the description. The name of the class is ideal for the filename of the language file.Digitiform
Many people use Reflections for member visibility overrides, which is BAD. Do not do that! But stating that use of Reflections in general is Voodoo and Doing It Wrong gives people the wrong impression. You shouldn't avoid them, you should understand them and know when they are beneficial and at which level of abstraction.Rentroll
Reflection is too slow for so simple task. Why not to use just explode("\\", get_class($object));?Markusmarl
@Markusmarl Slow? Possibly not, actually. But the relevant question is surely "why do you need the class name as a string?" It's not often the right solution to a problem.Secretary
@lonesomeday, thanks for the answer. Do you have some example when it wouldn't work? It'd be good to know...Markusmarl
@Markusmarl The question is "Why do you want the class name as a string?"Secretary
Hm... I don't know. I just want only short class name. :)Markusmarl
@VanjaD. "Many people use Reflections for member visibility overrides, which is BAD" — It is not "BAD" when you are doing it for the right reasons. Such as implementing features that PHP is missing. One such missing feature is the ability to update the properties of an instance with the properties of a previously serialized instance. #moral_judgementalism_is_so_tediousBrooksbrookshire
@Brooksbrookshire I've provided the code to do this, while noting that I personally can't think of a good use from it. That is a million miles from saying that there is no good use for it. If you're extrapolating from my answer to the general problems afflicting the human condition, you may just possibly be finding stuff that isn't there.Secretary
@Secretary — Suffice it to say that your commentary hit on one of my pet peeves; developers who "moralize" about programming techniques simple because they are unable to imagine appropriate use-cases. To me it speaks more about a lack of vision of the person standing in judgement than it does about inappropriateness of the technique. Hey, but don't worry; the vast majority of developers opine in this manner so it is not like you are unique.Brooksbrookshire
@VasiliiSuricov Can you clarify what you mean?Secretary
@Secretary i'll remove it, sorry. this comment was for next answer "is the best solution with regards to performance." - is not. how i've explained there preg_replace is fastest wayMinimum
S
201

(new \ReflectionClass($obj))->getShortName(); is the best solution with regards to performance.

I was curious which of the provided solutions is the fastest, so I've put together a little test.

Results

Reflection: 1.967512512207 s ClassA
Basename:   2.6840535163879 s ClassA
Explode:    2.6507515668869 s ClassA

Code

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

The results actually surprised me. I thought the explode solution would be the fastest way to go...

Soniferous answered 24/8, 2014 at 14:36 Comment(11)
Great answer. I was running the very same code but I got a different result (Macbook Pro i7, 16 GB ram). Reflection:0.382, Basename:0.380, Explode:0.399. I think it depends on your system what is best...Photocompose
Run PHP 10 000 times with that code and you get a better result. The above might fetch the reflection from some pool, but this is not the usual behaviour of the applications out there. They only need it once or twice.Aeciospore
I wonder does this test hold true when instantiating a ReflectionClass on a more substantial object than the small object of Class A in your test...Billfish
array_pop may be expensive. Try with end instead, at least then you aren't altering the array contents (although the difference might be trivial). For me reflection is 20% slower than explode, once I fix it so that the result of explode goes to a variable. Otherwise you get notice spam. A suppressed notice might impact performance more than you think.Soakage
You can also cache get_class, use CLASS, use self/static::class, might only be dealing with a string from elsewhere, etc. strrpos with substr is by far the fastest of all if you want speed. About twice to three times as fast in php7.1. In php 5.6 it's still strrpos > explode > reflection, however the difference is less pronounced.Soakage
running just one iteration instead of 100000 gives a much different result: Reflection: 1.0967254638672 100000th/s ClassA Basename: 0.81062316894531 100000th/s ClassA Explode: 0.50067901611328 100000th/s ClassANectarous
explode('\\', static::class)[0] ? doesn't it returns the first part of the namespace? should return last part, not firstBrazzaville
getClassExplode returns foo. PHP Version 7.2.24-0ubuntu0.18.04.4Minimum
1M iterations: 1st preg_replace('/^(\w+\\\)*/', '', static::class) = 0.185, 2nd (new \ReflectionClass($this))->getShortName() = 0.248, 3rd basename(str_replace('\\', '/', static::class)) = 0.558Minimum
10 iterations: the same range with 3.790, 5.317, 9.918 respectivelyMinimum
I believe this is misleading because ReflectionClass IMO triggers the autoloader which can lead to file I/O which will be much slower than string manipulation.Malo
B
116

I added substr to the test of https://mcmap.net/q/126980/-how-do-i-get-an-object-39-s-unqualified-short-class-name and that's the fastet way I could test (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9) both with an i5.

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

Results

Reflection: 0.068084406852722 s ClassA
Basename: 0.12301609516144 s ClassA
Explode: 0.14073524475098 s ClassA
Substring: 0.059865570068359 s ClassA 

Code

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==

As mentioned in the comments by @MrBandersnatch there is even a faster way to do this:

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

Here are the updated test results with "SubstringStrChr" (saves up to about 0.001 s):

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
Bimetallism answered 13/12, 2014 at 10:10 Comment(11)
Just because we listing for efficiency I found this to be the fastest, comparison from the test provided in this solution substr(strrchr(get_class($obj), '\\'), 1); Reflection: 0.084223914146423 s ClassA -- Basename: 0.13206427097321 s ClassA -- Explode: 0.15331919193268 s ClassA -- Substring: 0.068068099021912 s ClassA -- Strrchar: 0.06472008228302 s ClassA --Furtek
I just came across this thread and added an additional benchmark to test str_replace(__NAMESPACE__ . '\\', '', __CLASS__);. The results on a weak virtual machine showed it to be almost twice as fast as all of these. php -f bench.php Reflection: 0.44037771224976 s ClassA Basename: 0.48089025020599 s ClassA Explode: 0.54955270290375 s ClassA Substring: 0.38200764656067 s ClassA Frank's Custom Benchmark: 0.22782742977142 s ClassAMiltiades
@FranklinPStrube you didn't use an object as mentioned in the question (you used __CLASS__ and also __NAMESPACE__ which are pointing to the current file). Therefore it's faster. To be fair, I added your suggestion to the test and ran it. Keep in mind str_replace is slower than substr. Here are the results: Reflection: 0.070202589035034 s TestController Basename: 0.12093763881259 s TestController Explode: 0.12268789609273 s TestController Substring: 0.061004797617594 s TestController Consts: 0.057392239570618 s TestController Your function is the "Consts".Bimetallism
@MrBandersnatch you are correct. I tested your solution and it saved me about 0.001 s. I updated my answer with yours!Bimetallism
Instead of get_class($this) you might want to use some cases substr(strrchr(get_called_class(), '\\'), 1) for instance when you want to get Class name in parent class, traits etc.Simonides
Warning: this code does not work with classes in the global namespace (i.e.: their full name equals their short name)! I advice to test something like: if ($pos = strrchr(static::class, '\\')) { .. } else { ... }.Burglary
The latter code really suits my need, perfect! strtolower(substr(strrchr(MyClass::class, '\\'), 1));Sural
according to doc php.net/manual/en/function.strrchr.php only the first character is considered in strrchr. So: return substr(strrchr(get_class($this), '\'), 1);Pula
To make it work in the global namespace too, simply prepend the classname with a backslash :) - ie: $classNameShort = substr(strrchr('\\' . get_class($this), '\\'), 1);Aden
If you need to retrieve not just the unqualified class name but also the namespace then I'm sure that storing the index from strrpos in a variable and then using it to get both the base name and the namespace will be fastest even though I've not benchmarked it. Perhaps reflections can compete. In my code I was using parts of the namespace to find file paths.Levon
I think it's a micro optimization, but it looks like preg_replace is faster than all 5 of your end results. I've tested with a static string to not measure get_class performance as well, but that way preg_replace takes about 20% off the time of SubstringStrChr as you named it: preg_replace('#^.+\\\\#', '', $fqcn);Saltatorial
P
47

Here is a more easier way of doing this if you are using Laravel PHP framework :

<?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));
}
Pietrek answered 3/11, 2016 at 9:41 Comment(4)
This isn't a builtin php function, it looks like a helper function provided by laravel.Kolosick
I think he said thatTenderloin
Thanks, I'm using Laravel and this answer saved me a bunch of time.Aliquot
github.com/laravel/framework/blob/…Laellaertes
M
21

I use this:

basename(str_replace('\\', '/', get_class($object)));
Mareld answered 9/1, 2014 at 8:58 Comment(4)
You can also try: $className = explode('\\', basename(get_class($this))); $className = array_pop($className); to get the plain classname. Or use substr.Chichihaerh
Works only on Windows On Windows, both slash (/) and backslash () are used as directory separator character. In other environments, it is the forward slash (/) php.net/manual/en/function.basename.phpMusaceous
@Musaceous I just ran into this while moving from Windows to Ubuntu.... maddening. Wound up using the solution mentioned in MaBi's update.Sternick
@Musaceous How come works only on Windows? the question was regarding the fully qualified namespace name if I am not wrong also years ago, and namespaces are not OS specific, and always with a backslash like windows directory separator.Paget
S
18

To get the short name as an one-liner (since PHP 5.4):

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

It is a clean approach and reasonable fast.

Sheehan answered 14/8, 2014 at 12:49 Comment(1)
I wonder how this compares against a string extraction in benchmarks. It seems like this would be much slower.Corsair
Y
15

I found myself in a unique situation where instanceof could not be used (specifically namespaced traits) and I needed the short name in the most efficient way possible so I've done a little benchmark of my own. It includes all the different methods & variations from the answers in this question.

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

A list of the of the entire result is here but here are the highlights:

  • If you're going to use reflection anyways, using $obj->getShortName() is the fastest method however; using reflection only to get the short name it is almost the slowest method.
  • 'strrpos' can return a wrong value if the object is not in a namespace so while 'safe strrpos' is a tiny bit slower I would say this is the winner.
  • To make 'basename' compatible between Linux and Windows you need to use str_replace() which makes this method the slowest of them all.

A simplified table of results, speed is measured compared to the slowest method:

+-----------------+--------+
| 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%  |
+-----------------+--------+
Yakut answered 21/12, 2016 at 13:44 Comment(0)
T
8

You can use explode for separating the namespace and end to get the class name:

$ex = explode("\\", get_class($object));
$className = end($ex);
Toolmaker answered 1/2, 2018 at 6:46 Comment(0)
I
7

Yii way

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

Yii uses this method in its Gii code generator

Method documentation

This method is similar to the php function basename() except that it will treat both \ and / as directory separators, independent of the operating system. This method was mainly created to work on php namespaces. When working with real file paths, php's basename() should work fine for you. Note: this method is not aware of the actual filesystem, or path components such as "..".

More information:

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

Imparipinnate answered 16/4, 2017 at 17:48 Comment(2)
Welcome to Stack Overflow. Please provide more information for your answer. What does this do and how can one use it.Evocation
This worked for me on Windows but not on Linux, maybe because namespaces are in a form of Windows directories backslashes '\' , whereas linux basename considers directory separators forward slashes '/'. So I worked it around with strtr.' basename(strtr($class,'\\','/'))Paget
M
6

Here is simple solution for 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()));
        }
    }
}

What will be return?

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
}

Extended class name and namespace works well to:

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
}

What about class in global namespace?

namespace {

    class ClassWithoutNamespace {
        use \Names;
    }

    echo ClassWithoutNamespace::getNamespace() . PHP_EOL; // empty string
    echo ClassWithoutNamespace::getBaseClassName() . PHP_EOL; // ClassWithoutNamespace
}
Musaceous answered 28/2, 2014 at 12:35 Comment(0)
K
5

I know this is an old post but this is what i use - Faster than all posted above just call this method from your class, a lot quicker than using Reflection

namespace Foo\Bar\Baz;

class Test {
    public function getClass() {
        return str_replace(__NAMESPACE__.'\\', '', static::class);
    }
}
Kulp answered 22/1, 2019 at 22:59 Comment(1)
Unfortunately that only works if you're calling it in the class whose name you want, not on just any class name as a string.Kiona
L
3

If you need to know the class name that was called from inside a class, and don't want the namespace, you can use this one

$calledClass = get_called_class();
$name = strpos($calledClass, '\\') === false ?
    $calledClass : substr($calledClass, strrpos($calledClass, '\\') + 1);

This is great when you have a method inside a class which is extended by other classes. Furthermore, this also works if namespaces aren't used at all.

Example:

<?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)
Linchpin answered 21/9, 2016 at 12:54 Comment(0)
F
3

A good old regex seems to be faster than the most of the previous shown methods:

// both of the below calls will output: ShortClassName

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

So this works even when you provide a short class name or a fully qualified (canonical) class name.

What the regex does is that it consumes all previous chars until the last separator is found (which is also consumed). So the remaining string will be the short class name.

If you want to use a different separator (eg. / ) then just use that separator instead. Remember to escape the backslash (ie. \) and also the pattern char (ie. /) in the input pattern.

Foxhound answered 24/11, 2017 at 18:51 Comment(0)
M
3

Fastest that I found here for PHP 7.2 on Ububntu 18.04

preg_replace('/^(\w+\\\)*/', '', static::class)
Minimum answered 18/5, 2020 at 22:36 Comment(0)
F
2

You may get an unexpected result when the class doesn't have a namespace. I.e. get_class returns Foo, then $baseClass would be oo.

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

This can easily be fixed by prefixing get_class with a backslash:

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

Now also classes without a namespace will return the right value.

Fling answered 5/2, 2016 at 9:51 Comment(0)
B
2

Based on @MaBi 's answer, I made this:

trait ClassShortNameTrait
{
    public static function getClassShortName()
    {
        if ($pos = strrchr(static::class, '\\')) {
            return substr($pos, 1);
        } else {
            return static::class;
        }
    }
}

Which you may use like that:

namespace Foo\Bar\Baz;

class A
{
    use ClassShortNameTrait;
}

A::class returns Foo\Bar\Baz\A, but A::getClassShortName() returns A.

Works for PHP >= 5.5.

Burglary answered 31/5, 2016 at 16:8 Comment(0)
S
2

Here you go:

public function get_name()
{
   return str_replace(__NAMESPACE__ . '\\', '', __CLASS__);
}
Sevigny answered 30/6, 2022 at 11:53 Comment(1)
Careful, this does not work in some situations, such as traits (since __NAMESPACE__ refers to the namespace of the trait, whereas __CLASS__ refers to the final class, possibly in a different namespace). (this also means it could be used to detect such a scenario :D)Subterrane
M
1

Found on the documentation page of get_class, where it was posted by me at 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];
}

But the idea of namespaces is to structure your code. That also means that you can have classes with the same name in multiple namespaces. So theoretically, the object you pass could have the name (stripped) class name, while still being a totally different object than you expect.

Besides that, you might want to check for a specific base class, in which case get_class doesn't do the trick at all. You might want to check out the operator instanceof.

Merge answered 11/11, 2013 at 8:33 Comment(0)
A
0

Quoting php.net:

On Windows, both slash (/) and backslash () are used as directory separator character. In other environments, it is the forward slash (/).

Based on this info and expanding from arzzzen answer this should work on both Windows and Nix* systems:

<?php

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

Note: I did a benchmark of ReflectionClass against basename+str_replace+get_class and using reflection is roughly 20% faster than using the basename approach, but YMMV.

Armful answered 18/3, 2014 at 15:26 Comment(0)
S
0

The fastest and imho easiest solution that works in any environment is:

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

?>
Slot answered 8/4, 2014 at 21:54 Comment(2)
This is why I wish PHP had internal class information operators. Instantiating an external reflector to do what should be as simple as $Object->__class->getShortName() really pisses me off about PHP. Your approach works, but now you're putting concrete methods in your classes just to expose what should be a language construct.Polyhymnia
PHP without “concrete” (or should we call them procedural) functions is impossible. Let's wait for PHP 6 (well, if it ever comes).Slot
P
0
$shortClassName = join('',array_slice(explode('\\', $longClassName), -1));
Pile answered 12/9, 2014 at 21:36 Comment(0)
T
0

If you're just stripping name spaces and want anything after the last \ in a class name with namespace (or just the name if there's no '\') you can do something like this:

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

Basically it's regex to get any combination of characters or backslashes up and until the last backslash then to return only the non-backslash characters up and until the end of the string. Adding the ? after the first grouping means if the pattern match doesn't exist, it just returns the full string.

Tenderloin answered 13/3, 2017 at 21:29 Comment(0)
C
0

Because "ReflectionClass" can be version depend just use the follow:

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

or even clear

if(class_basename(ClassName::class) == 'ClassName') {
... do this ...
}
Coaptation answered 11/10, 2019 at 13:10 Comment(1)
class_basename is not standard php function, you need to install laravel (illuminate/helpers) to use it. Such solution is too heavy due to additional package requirements.Pulmonic
E
0

Just my small function which from all benchmarks runs fastest on my mac with PHP 8.1.6. This function handles situations when provided string is empty or doesn't have any namespace (doesn't contain \ character inside).

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

Benchmark (class without namespace or \):

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

Benchmark (full namespace):

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
Enteric answered 25/5, 2022 at 9:29 Comment(1)
How about strrchr? I know it sadly doesn't support the 3rd argument like strchr does, but seems to me like it would be best for the job.Breedlove

© 2022 - 2024 — McMap. All rights reserved.