Перейти к содержимому

Php определить класс который вызвал другой класс

  • автор:

Как узнать имя метода, который вызвал метод?

Из примера думаю суть ясна, как узнать имя класса нашел, мне бы теперь узнать имя дочернего метода который вызвал метод родителя, можно конечно это имя передать параметром, но так не интересно же.

  • Вопрос задан более трёх лет назад
  • 3445 просмотров

8 комментариев

Оценить 8 комментариев

qonand

И где здесь ООП? Класс от которого наследуются ничего не должен знать о классах которые его наследуют, это вообще не ООП подход

sanek_os9

Александр Шаповал @sanek_os9 Автор вопроса

Максим Федоров: он у меня умный потому знает кто дергает его методы, почему бы нет? Наверное я книжки плохо читал

Евгений @immaculate

Александр Шаповал: Такой подход — 99.99% знак говнокода. Или даже 100%. Не должны методы знать такую информацию. В нормальной архитектуре это ни к чему.

sanek_os9

Александр Шаповал @sanek_os9 Автор вопроса

Евгений: в своём случае, в методе display я подключаю файл шаблона, что бы в дочернем методе не передавать имя файла который нужно подключить я беру это имя из его названия и подключаю. В итоге получаю что какой метод вызывает display такой файл и подключаю, как по мне вполне юзабельно.

Евгений @immaculate

Александр Шаповал: Гораздо понятнее, проще, быстрее и красивее определить у класса атрибут типа template_name .

sanek_os9

Александр Шаповал @sanek_os9 Автор вопроса

Евгений: ну это тогда придется его определять у каждого метода (если в нем предусмотрен вывод), и хорошо когда этот атрибут соответствует имени метода, что бы когда смотришь шаблон было видно какой файл в каком классе используется, поэтому встает вопрос зачем указывать то, что заранее известно. Что касается понимания, тут все просто, достаточно один раз понять что файл шаблона подключается исходя из имени метода и класса.
Раньше я писал

class posts extends Controller < public function actionIndex() < $this->display('posts/index'); > >
class posts extends Controller < public function actionIndex() < $this->display(); > >

Один раз в методе display написал «не красиво» зато потом все красиво и структура файлов у шаблона тоже красива, потому что иначе он не будет работать.

Евгений @immaculate

Александр Шаповал: Поверьте моему опыту. Ради экономии 7-10 символов, вы усложнили код для понимания и изменения. И это потом выльется в часы отладки у вас или следующего разработчика.

sanek_os9

Александр Шаповал @sanek_os9 Автор вопроса

Евгений: спасибо за совет. Тут суть не только в сокращении кода а и содержании в порядке файлов шаблона, ведь легко можно там развести бардак. Пока оставлю как есть, а в дальнейшем если что, понесу всю ответственность:)

Как получить имя класса PHP

Как в родительском классе получить имя класса, который вызвал действие? Пример:

class ParentClass < function action() < echo $className; >> class ChildClass extends ParentClass <> $parentClass = new ParentClass(); $parentClass->action(); // ParentClass $childClass = new ChildClass(); $childClass->action(); // ChildClass 

Отслеживать

задан 1 фев 2014 в 15:42

NikolasSumrak NikolasSumrak

92 1 1 серебряный знак 7 7 бронзовых знаков

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Существуют так называемые «Волшебные константы», о которых можно почитать в официальном мануале.
Для решения вашей задачи определите метод, в котором возвращаете __CLASS__ , либо, как написал Etki — get_class($this) .

class ParentClass < function action() < return __CLASS__; >> 

Метод вернет полное название класса вместе с пространством имен. Чтобы получить только имя класса, можно разбить строку по \ и взять последний элемент.

class ParentClass < function action() < $array = explode('\\', __CLASS__); return $array[count($array) - 1]; >> 

get_called_class

Возвращает имя класса, из которого был вызван статический метод.

Список параметров

У этой функции нет параметров.

Возвращаемые значения

Возвращает имя класса.

Ошибки

Если функция get_called_class() вызывается не из класса, то выдаётся ошибка Error . До версии PHP 8.0.0 выдавалась ошибка уровня E_WARNING .

Список изменений

Версия Описание
8.0.0 Вызов функции не из класса теперь приводит к ошибке Error . Ранее выдавалась ошибка уровня E_WARNING и функция возвращала значение false .

Примеры

Пример #1 Пример использования get_called_class()

class foo static public function test () var_dump ( get_called_class ());
>
>

class bar extends foo >

foo :: test ();
bar :: test ();

Результат выполнения этого примера:

string(3) "foo" string(3) "bar"

Смотрите также

  • get_parent_class() — Возвращает имя родительского класса для объекта или класса
  • get_class() — Возвращает имя класса, к которому принадлежит объект
  • is_subclass_of() — Проверяет, содержит ли объект в своём дереве предков указанный класс либо прямо реализует его

User Contributed Notes 9 notes

9 years ago

As of PHP 5.5 you can also use «static::class» to get the name of the called class.

class Bar public static function test () var_dump (static::class);
>
>

class Foo extends Bar

string(3) «Foo»
string(3) «Bar»

10 years ago

get_called_class() in closure-scopes:

ABSTRACT CLASS Base
protected static $stub = [ ‘baz’ ];

//final public function boot()
static public function boot ()
print __METHOD__ . ‘-> ‘ . get_called_class (). PHP_EOL ;

array_walk (static:: $stub , function()
print __METHOD__ . ‘-> ‘ . get_called_class (). PHP_EOL ;
>);
>

public function __construct ()
self :: boot ();
print __METHOD__ . ‘-> ‘ . get_called_class (). PHP_EOL ;

array_walk (static:: $stub , function()
print __METHOD__ . ‘-> ‘ . get_called_class (). PHP_EOL ;
>);
>
>

CLASS Sub EXTENDS Base
>

// static boot
Base :: boot (); print PHP_EOL ;
// Base::boot -> Base
// Base:: -> Base

Sub :: boot (); print PHP_EOL ;
// Base::boot -> Sub
// Base:: -> Base

new sub ;
// Base::boot -> Sub
// Base:: -> Base
// Base->__construct -> Sub
// Base-> -> Sub

// instance boot
new sub ;
// Base->boot -> Sub
// Base-> -> Sub
// Base->__construct -> Sub
// Base-> -> Sub
?>

12 years ago

I think it is worth mentioning on this page, that many uses of the value returned by get_called_function() could be handled with the new use of the old keyword static, as in
static:: $foo ;
?>

versus
$that = get_called_class ();
$that :: $foo ;
?>

I had been using $that:: as my conventional replacement for self:: until my googling landed me the url above. I have replaced all uses of $that with static with success both as
static:: $foo ; //and.
new static();
?>

Since static:: is listed with the limitation: «Another difference is that static:: can only refer to static properties.» one may still need to use a $that:: to call static functions; though I have not yet needed this semantic.

3 years ago

namespace root;
class Factor protected static $instance = null;

private function __construct()

public static function getInstance() if (!self::$instance) $name = get_called_class();
self::$instance = new $name();
>

class Single extends Factor public function abc() return ‘abc’;
>
>

class Index public function get() return Single::getInstance();
>
>

$index = new Index();
var_dump($index->get());

Php определить класс который вызвал другой класс

Каждое определение класса начинается с ключевого слова class , затем следует имя класса, и далее пара фигурных скобок, которые заключают в себе определение свойств и методов этого класса.

Именем класса может быть любое слово, при условии, что оно не входит в список зарезервированных слов PHP, начинается с буквы или символа подчёркивания и за которым следует любое количество букв, цифр или символов подчёркивания. Если задать эти правила в виде регулярного выражения, то получится следующее выражение: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$ .

Класс может содержать собственные константы, переменные (называемые свойствами) и функции (называемые методами).

Пример #1 Простое определение класса

class SimpleClass
// объявление свойства
public $var = ‘значение по умолчанию’ ;

// объявление метода
public function displayVar () echo $this -> var ;
>
>
?>

Псевдопеременная $this доступна в том случае, если метод был вызван в контексте объекта. $this — значение вызывающего объекта.

Внимание

Вызов нестатического метода статически вызывает ошибку Error . До PHP 8.0.0 это привело бы к уведомлению об устаревании, и $this не была бы определена.

Пример #2 Некоторые примеры псевдо-переменной $this

class A
function foo ()
if (isset( $this )) echo ‘$this определена (‘ ;
echo get_class ( $this );
echo «)\n» ;
> else echo «\$this не определена.\n» ;
>
>
>

$a = new A ();
$a -> foo ();

$b = new B ();
$b -> bar ();

Результат выполнения этого примера в PHP 7:

$this определена (A) Deprecated: Non-static method A::foo() should not be called statically in %s on line 27 $this не определена. Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this не определена. Deprecated: Non-static method B::bar() should not be called statically in %s on line 32 Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this не определена.

Результат выполнения этого примера в PHP 8:

$this определена (A) Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27 Stack trace: #0 thrown in %s on line 27
Классы, доступные только для чтения

Начиная с PHP 8.2.0, класс может быть помечен модификатором readonly . Пометка класса как readonly добавит модификатор readonly к каждому объявленному свойству и предотвратит создание динамических свойств. Более того, невозможно добавить их поддержку с помощью атрибута AllowDynamicProperties . Попытка это сделать приведёт к ошибке компиляции.

#[ \AllowDynamicProperties ]
readonly class Foo >

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>

Поскольку ни нетипизированные, ни статические свойства не могут быть помечены модификатором readonly , классы, доступные только для чтения также не могут их объявлять:

// Fatal error: Readonly property Foo::$bar must have type
?>

readonly class Foo
public static int $bar ;
>

// Fatal error: Readonly class Foo cannot declare static properties
?>

Класс readonly может быть расширен тогда и только тогда, когда дочерний класс также является классом readonly .

new

Для создания экземпляра класса используется директива new . Новый объект всегда будет создан, за исключением случаев, когда он содержит конструктор, в котором определён вызов исключения в случае возникновения ошибки. Рекомендуется определять классы до создания их экземпляров (в некоторых случаях это обязательно).

Если с директивой new используется строка ( string ), содержащая имя класса, то будет создан новый экземпляр этого класса. Если имя находится в пространстве имён, то оно должно быть задано полностью.

Замечание:

В случае отсутствия аргументов в конструктор класса, круглые скобки после названия класса можно опустить.

Пример #3 Создание экземпляра класса

// Это же можно сделать с помощью переменной:
$className = ‘SimpleClass’ ;
$instance = new $className (); // new SimpleClass()
?>

Начиная с PHP 8.0.0, поддерживается использование оператора new с произвольными выражениями. Это позволяет создавать более сложные экземпляры, если выражение представлено в виде строки ( string ). Выражения должны быть заключены в круглые скобки.

Пример #4 Создание экземпляра с использованием произвольного выражения

В данном примере мы показываем несколько вариантов допустимых произвольных выражений, которые представляют имя класса. Пример вызова функции, конкатенации строк и константы ::class .

class ClassA extends \stdClass <>
class ClassB extends \stdClass <>
class ClassC extends ClassB <>
class ClassD extends ClassA <>

function getSomeClass (): string
return ‘ClassA’ ;
>

var_dump (new ( getSomeClass ()));
var_dump (new ( ‘Class’ . ‘B’ ));
var_dump (new ( ‘Class’ . ‘C’ ));
var_dump (new ( ClassD ::class));
?>

Результат выполнения этого примера в PHP 8:

object(ClassA)#1 (0) < >object(ClassB)#1 (0) < >object(ClassC)#1 (0) < >object(ClassD)#1 (0)

В контексте класса можно создать новый объект через new self и new parent .

Когда происходит присвоение уже существующего экземпляра класса новой переменной, то эта переменная будет указывать на этот же экземпляр класса. То же самое происходит и при передаче экземпляра класса в функцию. Копию уже созданного объекта можно создать через её клонирование.

Пример #5 Присваивание объекта

$instance = new SimpleClass ();

$assigned = $instance ;
$reference =& $instance ;

$instance -> var = ‘$assigned будет иметь это значение’ ;

$instance = null ; // $instance и $reference становятся null

var_dump ( $instance );
var_dump ( $reference );
var_dump ( $assigned );
?>

Результат выполнения этого примера:

NULL NULL object(SimpleClass)#1 (1) < ["var"]=>string(30) "$assigned будет иметь это значение" >

Создавать экземпляры объекта можно двумя способами:

Пример #6 Создание новых объектов

class Test
static public function getNew ()
return new static;
>
>

class Child extends Test
<>

$obj1 = new Test ();
$obj2 = new $obj1 ;
var_dump ( $obj1 !== $obj2 );

$obj3 = Test :: getNew ();
var_dump ( $obj3 instanceof Test );

$obj4 = Child :: getNew ();
var_dump ( $obj4 instanceof Child );
?>

Результат выполнения этого примера:

bool(true) bool(true) bool(true)

Обратиться к свойству или методу только что созданного объекта можно с помощью одного выражения:

Пример #7 Доступ к свойствам/методам только что созданного объекта

echo (new DateTime ())-> format ( ‘Y’ );
?>

Результатом выполнения этого примера будет что-то подобное:

2016

Замечание: До PHP 7.1 аргументы не имели значения, если не определена функция конструктора.

Свойства и методы

Свойства и методы класса живут в разделённых «пространствах имён», так что возможно иметь свойство и метод с одним и тем же именем. Ссылки как на свойства, так и на методы имеют одинаковую нотацию, и получается, что получите вы доступ к свойству или же вызовете метод — определяется контекстом использования.

Пример #8 Доступ к свойству vs. вызов метода

public function bar () return ‘метод’ ;
>
>

$obj = new Foo ();
echo $obj -> bar , PHP_EOL , $obj -> bar (), PHP_EOL ;

Результат выполнения этого примера:

свойство метод

Это означает, что вызвать анонимную функцию, присвоенную переменной, напрямую не получится. Вместо этого свойство должно быть назначено, например, переменной. Можно вызвать такое свойство напрямую, заключив его в скобки.

Пример #9 Вызов анонимной функции, содержащейся в свойстве

public function __construct () $this -> bar = function() return 42 ;
>;
>
>

echo ( $obj -> bar )(), PHP_EOL ;

Результат выполнения этого примера:

extends

Класс может наследовать константы, методы и свойства другого класса используя ключевое слово extends в его объявлении. Невозможно наследовать несколько классов, один класс может наследовать только один базовый класс.

Наследуемые константы, методы и свойства могут быть переопределены (за исключением случаев, когда метод или константа класса объявлены как final) путём объявления их с теми же именами, как и в родительском классе. Существует возможность доступа к переопределённым методам или статическим свойствам путём обращения к ним через parent::

Замечание: Начиная с PHP 8.1.0, константы можно объявлять окончательными (final).

Пример #10 Простое наследование классов

class ExtendClass extends SimpleClass
// Переопределение метода родителя
function displayVar ()
echo «Расширенный класс\n» ;
parent :: displayVar ();
>
>

$extended = new ExtendClass ();
$extended -> displayVar ();
?>

Результат выполнения этого примера:

Расширенный класс значение по умолчанию
Правила совместимости сигнатуры

При переопределении метода его сигнатура должна быть совместима с родительским методом. В противном случае выдаётся фатальная ошибка или, до PHP 8.0.0, генерируется ошибка уровня E_WARNING . Сигнатура является совместимой, если она соответствует правилам контравариантности, делает обязательный параметр необязательным, добавляет только необязательные новые параметры и не ограничивает, а только ослабляет видимость. Это известно как принцип подстановки Барбары Лисков или сокращённо LSP. Правила совместимости не распространяются на конструктор и сигнатуру private методов, они не будут выдавать фатальную ошибку в случае несоответствия сигнатуры.

Пример #11 Совместимость дочерних методов

class Base
public function foo ( int $a ) echo «Допустимо\n» ;
>
>

class Extend1 extends Base
function foo ( int $a = 5 )
parent :: foo ( $a );
>
>

class Extend2 extends Base
function foo ( int $a , $b = 5 )
parent :: foo ( $a );
>
>

$extended1 = new Extend1 ();
$extended1 -> foo ();
$extended2 = new Extend2 ();
$extended2 -> foo ( 1 );

Результат выполнения этого примера:

Допустимо Допустимо

Следующие примеры демонстрируют, что дочерний метод, который удаляет параметр или делает необязательный параметр обязательным, несовместим с родительским методом.

Пример #12 Фатальная ошибка, когда дочерний метод удаляет параметр

class Base
public function foo ( int $a = 5 ) echo «Допустимо\n» ;
>
>

class Extend extends Base
function foo ()
parent :: foo ( 1 );
>
>

Результат выполнения этого примера в PHP 8 аналогичен:

Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13

Пример #13 Фатальная ошибка, когда дочерний метод делает необязательный параметр обязательным.

class Base
public function foo ( int $a = 5 ) echo «Допустимо\n» ;
>
>

class Extend extends Base
function foo ( int $a )
parent :: foo ( $a );
>
>

Результат выполнения этого примера в PHP 8 аналогичен:

Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13

Внимание

Переименование параметра метода в дочернем классе не является несовместимостью сигнатуры. Однако это не рекомендуется, так как приведёт к Error во время выполнения, если используются именованные аргументы.

Пример #14 Ошибка при использовании именованных аргументов и параметров, переименованных в дочернем классе

class A public function test ( $foo , $bar ) <>
>

class B extends A public function test ( $a , $b ) <>
>

// Передача параметров согласно контракту A::test()
$obj -> test ( foo : «foo» , bar : «bar» ); // ОШИБКА!

Результатом выполнения этого примера будет что-то подобное:

Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14 Stack trace: #0 thrown in /in/XaaeN on line 14

::class

Ключевое слово class используется для разрешения имени класса. Чтобы получить полное имя класса ClassName , используйте ClassName::class . Обычно это довольно полезно при работе с классами, использующими пространства имён.

Пример #15 Разрешение имени класса

Результат выполнения этого примера:

NS\ClassName

Замечание:

Разрешение имён класса с использованием ::class происходит на этапе компиляции. Это означает, что на момент создания строки с именем класса автозагрузки класса не происходит. Как следствие, имена классов раскрываются, даже если класс не существует. Ошибка в этом случае не выдаётся.

Пример #16 Отсутствует разрешение имени класса

print Does\Not\Exist ::class;
?>

Результат выполнения этого примера:

Does\Not\Exist

Начиная с PHP 8.0.0, константа ::class также может использоваться для объектов. Это разрешение происходит во время выполнения, а не во время компиляции. То же самое, что и при вызове get_class() для объекта.

Пример #17 Разрешение имени объекта

namespace NS class ClassName >
>
$c = new ClassName ();
print $c ::class;
?>

Результат выполнения этого примера:

NS\ClassName

Методы и свойства Nullsafe

Начиная с PHP 8.0.0, к свойствам и методам можно также обращаться с помощью оператора «nullsafe»: ?-> . Оператор nullsafe работает так же, как доступ к свойству или методу, как указано выше, за исключением того, что если разыменование объекта выдаёт null , то будет возвращён null , а не выброшено исключение. Если разыменование является частью цепочки, остальная часть цепочки пропускается.

Аналогично заключению каждого обращения в is_null() , но более компактный.

Пример #18 Оператор Nullsafe

// Начиная с PHP 8.0.0, эта строка:
$result = $repository ?-> getUser ( 5 )?-> name ;

// Эквивалентна следующему блоку кода:
if ( is_null ( $repository )) $result = null ;
> else $user = $repository -> getUser ( 5 );
if ( is_null ( $user )) $result = null ;
> else $result = $user -> name ;
>
>
?>

Замечание:

Оператор nullsafe лучше всего использовать, когда null считается допустимым и ожидаемым значением для возвращаемого свойства или метода. Для индикации ошибки предпочтительнее выбрасывать исключение.

User Contributed Notes 11 notes

16 years ago

I was confused at first about object assignment, because it’s not quite the same as normal assignment or assignment by reference. But I think I’ve figured out what’s going on.

First, think of variables in PHP as data slots. Each one is a name that points to a data slot that can hold a value that is one of the basic data types: a number, a string, a boolean, etc. When you create a reference, you are making a second name that points at the same data slot. When you assign one variable to another, you are copying the contents of one data slot to another data slot.

Now, the trick is that object instances are not like the basic data types. They cannot be held in the data slots directly. Instead, an object’s «handle» goes in the data slot. This is an identifier that points at one particular instance of an obect. So, the object handle, although not directly visible to the programmer, is one of the basic datatypes.

What makes this tricky is that when you take a variable which holds an object handle, and you assign it to another variable, that other variable gets a copy of the same object handle. This means that both variables can change the state of the same object instance. But they are not references, so if one of the variables is assigned a new value, it does not affect the other variable.

// Assignment of an object
Class Object public $foo = «bar» ;
>;

$objectVar = new Object ();
$reference =& $objectVar ;
$assignment = $objectVar

//
// $objectVar —>+———+
// |(handle1)—-+
// $reference —>+———+ |
// |
// +———+ |
// $assignment —>|(handle1)—-+
// +———+ |
// |
// v
// Object(1):foo=»bar»
//
?>

$assignment has a different data slot from $objectVar, but its data slot holds a handle to the same object. This makes it behave in some ways like a reference. If you use the variable $objectVar to change the state of the Object instance, those changes also show up under $assignment, because it is pointing at that same Object instance.

$objectVar -> foo = «qux» ;
print_r ( $objectVar );
print_r ( $reference );
print_r ( $assignment );

//
// $objectVar —>+———+
// |(handle1)—-+
// $reference —>+———+ |
// |
// +———+ |
// $assignment —>|(handle1)—-+
// +———+ |
// |
// v
// Object(1):foo=»qux»
//
?>

But it is not exactly the same as a reference. If you null out $objectVar, you replace the handle in its data slot with NULL. This means that $reference, which points at the same data slot, will also be NULL. But $assignment, which is a different data slot, will still hold its copy of the handle to the Object instance, so it will not be NULL.

$objectVar = null ;
print_r ( $objectVar );
print_r ( $reference );
print_r ( $assignment );

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *