php get classname without namespace
How do I get an object’s unqualified (short) class name?
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.
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.
22 Answers 22
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:
(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
Code
The results actually surprised me. I thought the explode solution would be the fastest way to go.
I added substr to the test of https://stackoverflow.com/a/25472778/2386943 and that’s the fastet way I could test (CentOS PHP 5.3.3, Ubuntu PHP 5.5.9) both with an i5.
Results
Code
==UPDATE==
As mentioned in the comments by @MrBandersnatch there is even a faster way to do this:
Here are the updated test results with «SubstringStrChr» (saves up to about 0.001 s):
Here is a more easier way of doing this if you are using Laravel PHP framework :
To get the short name as an one-liner (since PHP 5.4):
It is a clean approach and reasonable fast.
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.
A list of the of the entire result is here but here are the highlights:
A simplified table of results, speed is measured compared to the slowest method:
get_class
(PHP 4, PHP 5, PHP 7, PHP 8)
get_class — Возвращает имя класса, к которому принадлежит объект
Описание
Список параметров
Тестируемый объект. Внутри класса этот параметр может быть опущен.
Возвращаемые значения
Если параметр object опущен внутри класса, будет возвращено имя этого класса.
Если параметр object является экземпляром класса, существующего в пространстве имён, то будет возвращено полное имя с указанием пространства имён.
Ошибки
Список изменений
Версия | Описание |
---|---|
7.2.0 | До этой версии значением по умолчанию для object было null с тем же эффектом, что и отсутствие передачи значения. Теперь null был удалён как значение по умолчанию для object и больше не является допустимым значением. |
Примеры
Пример #1 Использование get_class()
// создание объекта
$bar = new foo ();
Результат выполнения данного примера:
Пример #2 Использование get_class() в родительском классе
class foo extends bar <
>
Результат выполнения данного примера:
Пример #3 Использование get_class() с классами в пространствах имён
namespace Foo \ Bar ;
class Baz <
public function __construct ()
<
$baz = new \ Foo \ Bar \ Baz ;
Результат выполнения данного примера:
Смотрите также
User Contributed Notes 36 notes
::class
fully qualified class name, instead of get_class
namespace my \ library \ mvc ;
print Dispatcher ::class; // FQN == my\library\mvc\Dispatcher
$disp = new Dispatcher ;
(For reference, here’s the debug code used. c() is a benchmarking function that runs each closure run 10,000 times.)
If you are using namespaces this function will return the name of the class including the namespace, so watch out if your code does any checks for this. Ex:
class Foo
<
public function __construct ()
<
echo «Foo» ;
>
>
People seem to mix up what __METHOD__, get_class($obj) and get_class() do, related to class inheritance.
Here’s a good example that should fix that for ever:
class Bar extends Foo <
$foo = new Foo ();
$bar = new Bar ();
$quux = new Quux ();
—doMethod—
Foo::doMethod
Foo::doMethod
Quux::doMethod
—doGetClassThis—
Foo::doThat
Bar::doThat
Quux::doThat
—doGetClass—
Foo::doThat
Foo::doThat
Quux::doThat
In Perl (and some other languages) you can call some methods in both object and class (aka static) context. I made such a method for one of my classes in PHP5, but found out that static methods in PHP5 do not ‘know’ the name of the calling subclass’, so I use a backtrace to determine it. I don’t like hacks like this, but as long as PHP doesn’t have an alternative, this is what has to be done:
Simplest way how to gets Class without namespace
namespace a \ b \ c \ d \ e \ f ;
echo new Foo (); // prints Foo
?>
Need a quick way to parse the name of a class when it’s namespaced? Try this:
/**
* Obtains an object class name without namespaces
*/
function get_real_class($obj) <
$classname = get_class($obj);
With regard to getting the class name from a namespaced class name, then using basename() seems to do the trick quite nicely.
namespace Foo \ Bar ;
class Snafu extends Baz
<
>
__CLASS__ Foo\Bar\Baz Baz
get_called_class Foo\Bar\Snafu Snafu
The code in my previous comment was not completely correct. I think this one is.
/**
* Returns the classname of the child class extending this class
*
* @return string The class name
*/
private static function getClass() <
$implementing_class = static::$__CLASS__;
$original_class = __CLASS__;
There are discussions below regarding how to create a singleton that allows subclassing. It seems with get_called_class there is now a cleaner solution than what is discussed below, that does not require overriding a method per subclass.
private function __construct () <
// Singleton
>
>
class MySubclass extends MySuperclass <
>
Although you can call a class’s static methods from an instance of the class as though they were object instance methods, it’s nice to know that, since classes are represented in PHP code by their names as strings, the same thing goes for the return value of get_class():
If you want the path to an file if you have i file structure like this
and foo() in foo.php extends controller() in controller.php like this
namespace system \ modules \ foo ;
class foo extends \ system \ libs \ controller <
public function __construct () <
parent :: __construct ();
>
>
?>
and you want to know the path to foo.php in controller() this may help you
namespace system \ libs ;
well, if you call get_class() on an aliased class, you will get the original class name
Attempting various singleton base class methods described on this page, I have created a base class and bridge function that allows it to work without get_called_class() if it’s not available. Unlike other methods listed here, I chose not to prevent use of __construct() or __clone().
default: throw new Exception ( «Unknown backtrace method type» );
>
>
>
class B extends Singleton <
>
class C extends Singleton <
>
Method for pulling the name of a class with namespaces pre-stripped.
namespace testme \ here ;
public function test ()
<
return get_class_name ( get_class ());
>
>
As noted in bug #30934 (which is not actually a bug but a consequence of a design decision), the «self» keyword is bound at compile time. Amongst other things, this means that in base class methods, any use of the «self» keyword will refer to that base class regardless of the actual (derived) class on which the method was invoked. This becomes problematic when attempting to call an overridden static method from within an inherited method in a derived class. For example:
public static function classDisplayName ()
<
return ‘Base Class’ ;
>
public static function classDisplayName ()
<
return ‘Derived Class’ ;
>
>
However, assuming compile-time binding (where the keyword «self» refers to the class in which the method is defined), which is how php works, the output would be:
The oddity here is that «$this» is bound at runtime to the actual class of the object (obviously) but «self» is bound at compile-time, which seems counter-intuitive to me. «self» is ALWAYS a synonym for the name of the class in which it is written, which the programmer knows so s/he can just use the class name; what the programmer cannot know is the name of the actual class on which the method was invoked (because the method could be invoked on a derived class), which it seems to me is something for which «self» ought to be useful.
However, questions about design decisions aside, the problem still exists of how to achieve behaviour similar to «self» being bound at runtime, so that both static and non-static methods invoked on or from within a derived class act on that derived class. The get_class() function can be used to emulate the functionality of runtime binding for the «self» keyword for static methods:
public static function classDisplayName ()
<
return ‘Base Class’ ;
>
public static function classDisplayName ()
<
return ‘Derived Class’ ;
>
>
I realise that some people might respond «why don’t use just just the class name with ‘ Class’ appended instead of the classDisplayName() method», which is to miss the point. The point is not the actual strings returned but the concept of wanting to use the real class for an overridden static method from within an inherited non-static method. The above is just a simplified version of a real-world problem that was too complex to use as an example.
Apologies if this has been mentioned before.
Неймспейсы и автозагрузка в PHP
В этом уроке мы коснемся архитектуры приложений. Если быть точнее – мы научимся тому, как в современном программировании на PHP принято хранить классы в отдельных файлах, и о том, как избегать при этом бесконечных строчек с include и require для подключения этих файлов.
На самом деле, в PHP всё довольно просто с правилами по реализации большинства частей приложения. Для этого есть уже придуманные умными людьми стандарты – PSR (PHP Standards Recommendations). В них описано, как нужно писать ту или иную составляющую вашей программы.
В этом уроке мы затронем стандарт PSR-4. В нём говорится о том, что каждый класс должен храниться в отдельном файле и находиться в пространстве имён. Давайте обо всём по порядку.
Пусть у нас есть классы User и Article. Нам нужно сохранить их в разных файлах. Для этого давайте создадим рядом с папкой www папку src, а внутри неё папку MyProject. Внутри папки MyProject создадим папку Models, а в ней создадим ещё 2 папки – Articles и Users. И уже в этих папках создадим файлы Article.php и User.php. Должно получиться следующее:
Давайте теперь опишем в этих двух файлах наши классы.
src/MyProject/Models/Articles/Article.php
Первую часть сделали – теперь у нас каждый класс лежит в отдельном файле. Давайте теперь перейдём в наш index.php, лежащий в директории www и запишем в него логику для работы с этими классами.
Давайте теперь попробуем запустить этот скрипт в браузере.
Разумеется, мы получим ошибку.
Нашему скрипту не удалось найти класс User. Давайте подключим файлы с нужными нам классами в начале index.php
Если мы сейчас запустим этот скрипт, то всё у нас прекрасно отработает и мы увидим результат var_dump().
Итак, с первым пунктом про хранение классов в отдельных файлах мы разобрались.
Теперь вернёмся к пространствам имён – неймспейсам. Тут всё довольно просто – класс можно поместить в отдельное именованное пространство и в дальнейшем использовать его по этому полному имени. Для того чтобы указать это пространство для конкретного класса используется слово namespace, за которым следует само имя. Указывается оно в файле с классом, перед определением класса. На примере класса User это будет выглядеть следующим образом:
src/MyProject/Models/Users/User.php
Теперь мы можем говорить, что класс User находится в неймспейсе MyProject\Models\Users.
Давайте проделаем аналогичные действия с классом Article.
src/MyProject/Models/Articles/Article.php
Теперь, чтобы в файле index.php работать с данными классами, мы должны указать полное имя класса – это имя класса с указанием его неймспейса. Делается это следующим образом.
www/index.php
Если мы сейчас запустим скрипт, то снова столкнёмся с ошибкой.
Но на этот раз, она уже другая. А именно – третий аргумент, переданный в конструктор класса Article должен быть объектом класса MyProject\Models\Articles\User, а передан объект класса MyProject\Models\Users\User. Заметили ошибку? Неймспейс не тот. Дело в том, что если в файле с классом указан неймспейс, то все классы, которые указываются в данном файле будут искаться в том же неймспейсе. Так как у нас класс User находится в другом неймспейсе, то мы должны явно это указать. Вот так:
src/MyProject/Models/Articles/Article.php
Либо же указать в начале файла о каком классе идёт речь, когда мы используем в коде только слово User. Делается это с помощью слова use после указания текущего неймспейса, но перед описанием класса.
Теперь, когда мы будем использовать класс User, то автоматически будет использоваться класс из неймспейса MyProject\Models\Users\User.
Давайте снова запустим скрипт, и убедимся, что всё у нас теперь работает.
Получили работающий скрипт. Ура! Вот в принципе и всё, что вам нужно знать о неймспейсах. В наших будущих программах мы всегда будем создавать классы внутри неймспейсов.
Автозагрузка
Однако, давайте снова посмотрим на наш файл index.php. представьте, что у нас теперь большой проект и в нём больше 100 классов. Нам придётся сто раз писать require с указанием каждого файла. Утомительно, да? Однако, можно автоматизировать этот процесс, написав функцию автозагрузки классов. Она будет вызываться каждый раз, когда впервые будет встречаться новый класс.
Итак, давайте сделаем эту функцию автозагрузки. Давайте я сначала приведу пример кода, а затем объясню, как это работает. Наш файл index.php принимает следующий вид:
А теперь по порядку о том, что же происходит.
Всё! Теперь все классы будут подгружаться автоматически. Давайте запустим скрипт и убедимся, что всё работает.
Снова запустим скрипт и посмотрим на вывод.
Мы видим, что в эту функцию попал сначала класс MyProject\Models\Users\User, а затем MyProject\Models\Articles\Article. И для этих классов мы сделали require нужных файлов и они успешно подгрузились.
На этом давайте var_dump уберём.
В функцию spl_autoload_register можно и вовсе передать не имя функции, а прямо саму функцию – не будем сейчас на этом останавливаться более детально. Просто знайте, что так можно:
В таком случае, функция называется анонимной – у неё нет имени. Она просто передаётся в качестве аргумента и имя ей не нужно.
Запустите код ещё раз, и убедитесь, что всё работает как нужно.
Вот такими вот нехитрыми действиями мы сделали автозагрузку классов. PHP – прекрасный язык, не правда ли?
Начиная с текущего урока я решил выкладывать итоговые результаты уроков на github, чтобы вам в случае чего можно было свериться с кодом, который должен был получиться в конце урока. Вот ссылка на результат этого урока.
Get class name from file
I have a php file which contains only one class. how can I know what class is there by knowing the filename? I know I can do something with regexp matching but is there a standard php way? (the file is already included in the page that is trying to figure out the class name).
11 Answers 11
There are multiple possible solutions to this problem, each with their advantages and disadvantages. Here they are, it’s up to know to decide which one you want.
Tokenizer
This method uses the tokenizer and reads parts of the file until it finds a class definition.
Advantages
Disadvantages
Code
Regular expressions
Use regular expressions to parse the beginning of the file, until a class definition is found.
Advantages
Disadvantages
Code
Note: The regex can probably be improved, but no regex alone can do this perfectly.
Get list of declared classes
This method uses get_declared_classes() and look for the first class defined after an include.
Advantages
Disadvantages
Code
Note: You cannot simply do end() as others suggested. If the class includes another class, you will get a wrong result.
This is the Tokenizer solution, modified to include a $namespace variable containing the class namespace, if applicable:
Say you have this class:
. or the alternative syntax:
You should have the following result:
You could also use the above to detect the namespace a file declares, regardless of it containing a class or not.
Пространства имен в PHP, разъяснение
Прим.пер.: Я в курсе, что на момент перевода актуальная версия PHP — 5.5, а также что есть мудрая книга мануал. Но мне показалось интересным, то как автор преподносит namespace функционал, возможно кому-то из тех, кто только постигает азы (да и не только, есть немало бородатых разработчиков, остановившихся на PHP 5.2), статья поможет проникнуться. Ходор.
Глобальное пространство имен
Вот такой, очень простой класс:
Ничего особенно, как видите, и если вы хотите использовать его, просто сделайте так:
Хорошо, хорошо, извини. Суть в том, что мы можем думать об этом классе, как находящимся в глобальном пространстве имён.Я не совсем уверен, что это правильный термин, но на мой взгляд это звучит вполне уместно. Собственно, это значит то, что класс не принадлежит никакому пакету, просто обычный класс.
Простое использование пространств имён
Давайте создадим еще одного Эддарда, рядом с тем, глобальным.
Здесь у нас очень похожий класс с одним небольшим изменением, добавлена директива пространства имен. Строка namespace Stark; говорит PHP что мы работаем в пространстве имен Stark и любой код (объявление классов, функций, переменных и т.д.) будет относиться к нему.
Итак, нам нужно создать нового Эдда, если вы решили что это нужно сделать вот так:
То нет, это не так. Здесь мы получаем экземпляр класса из первого примера, который мы создали ранее. Не тот, в пространстве имен Stark. Давайте попробуем создать экземпляр Эддарда Старка.
Для создания экземпляра класса нам нужно предварить имя класса префиксом из названия пространства имен, которому класс принадлежит, а в качестве разделителя использовать обратную косую черту. В итоге у нас есть экземпляр именно того класса, что нам нужен. Разве это не волшебно?
К слову сказать, пространства имён могут образовывать сколь угодно сложную иерархию, используя столько уровней, сколько потребуется. Например:
Теория относительности
Помните, как я сказал вам, что PHP всегда работает относительно текущего пространства имен. Давайте взглянем на это в действии:
Добавив директиву пространства имён, мы дали понять PHP, что мы находимся в пространстве имён Stark. Так как именно в нем мы определили класс Eddard, то именно его мы и получим. Видите — все относительно.
Сейчас, когда мы изменили пространство имён, у нас возникла одна маленькая проблема. Есть идеи, о чем я? А как нам теперь получить наш оригинальный класс Eddard? Ну тот, который в глобальном пространстве?
К счастью в PHP есть трюк, который позволит нам решить эту проблему — просто добавив \ к имени класса.
Видя ведущий слеш PHP понимает, что нужно выглянуть за пределы текущего namespace и создает экземпляр нужного нам класса.
А сейчас включи свое воображение. Представь, что у нас есть класс из другого пространства имен, названный Tully\Edmure. Сейчас нам нужно использовать его внутри пространства Stark. И как нам это сделать?
И снова нам пришлось использовать обратный слеш, чтобы перейти к глобальной видимости, прежде чем создать экземпляр класса в пространстве Tully.
Вообще, ссылаться вот так на классы из других пространств имен, используя полную иерархию в названии, может быть довольно утомительно. Но к счастью, есть возможность сделать ярлык, давайте посмотрим:
А, еще один маленький трюк! Мы можем дать нашим импортируемым классам прозвища:
Давая Daenerys из пространства Dothraki прозвище Khaleesi, мы можем использовать оба класса Daenerys. Довольно удобно, там мы можем использовать все необходимые классы в нашем приложении.
Структура
Пространства имен также могут помочь нам в организации нашего кода. Позвольте, я продемонстрирую.
Скажем, я хочу создать библиотеку с открытым исходным кодом. Мне бы очень хотелось, чтобы другие могли использовать мой код, это было бы здорово! Беда в том, что имена классов в моем коде конфликтовали с собственным приложением пользователя моей библиотеки. Это было бы ужасно неудобно. Вот как я решу эту проблему:
Здесь я использовал свое имя, чтобы показать, что код принадлежит мне, и отделить свой код от кода пользователя моей библиотеки. Внутри базового пространства имен я создал структуру классов в соответствии с их иерархией.
Начав использовать composer, вы узнаете, как использовать пространства имён для упрощения автозагрузки кода. Я настоятельно рекомендую вам взглянуть на этот полезный механизм.
Недостатки
По правде говоря, я чувствую себя немного виноватым за то, что назвал этот подзаголовок «Недостатки». То, о чем я собираюсь говорить, на самом деле ошибкой не является.
Дело в том, что в других языках функционал пространств имён реализован похожим образом, и при этом языки обеспечивают дополнительный функционал для взаимодействия с пространствами имён.
В Java, например, вы можете импортировать несколько классов в текущее пространство имен, используя оператор импорта. В Java, import является аналогом use и он использует точки, чтобы отделить вложенные пространства имен (или пакеты). Вот пример:
В PHP у вас так не выйдет. Вы должны импортировать каждый класс в отдельности. Извините. Собственно, почему я извиняюсь? Идите и жалуйтесь команде разработчиков PHP, но я прошу вас — будьте вежливы. Они сделали много интересного в последнее время.
Вот изящный трюк, чтобы немного сгладить озвученную проблему. Представьте себе, что у нас есть структура классов из предыдущего примера. Мы можем взять часть подпространства и дать ему псевдоним.
Это может быть полезным при использовании большого числа классов. Добра всем!
Все пожелания и предложения с радостью приму в личку, спасибо.