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

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

  • автор:

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

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

Чтобы наследовать один класс от другого, нам надо применить оператор extends . Стоит отметить, что в PHP мы можем унаследовать класс только от одного класса. Множественное наследование не поддерживается.

Например, унаследуем класс Employee от класса Person :

name = $name; > function displayInfo() < echo "Имя: $this->name
"; > > class Employee extends Person <> $tom = new Employee("Tom"); $tom -> displayInfo(); ?>

В данном случае предположим, что класс Person представляет человека в целом, а класс Employee — работника некого предприятия. В этой связи каждый работник преддставляет человека. И чтобы не дублировать один и тот же функционал, лучше в данном случае унаследовать класс работника — Employee от класа человека — Person. В этой паре класс Person еще называется родительским или базовым классом, а класс — Employee — производным классом или классом-наследником.

И так как класс Employee унаследован от Person, для объектов класса Employee мы можем использовать функционал родительского класса Person. Так, для создания объекта Employee в данном случае вызывается конструктор, который определен в классе Person и который в качестве параметра принимает имя человека:

$tom = new Employee("Tom");

И также у переменной типа Employee вызывается метод displayInfo , который определен в классе Person:

$tom -> displayInfo();

Переопределение функционала

Унаследовав функционал от родительского класса класс-наследник может добавить свои свойства и методы или переопредилить унаследованный функционал. Например, изменим класс Employee, добавив в него данные о компании, где работает работник:

name = $name; > function displayInfo() < echo "Имя: $this->name
"; > > class Employee extends Person < public $company; function __construct($name, $company) < $this->name = $name; $this->company = $company; > function displayInfo() < echo "Имя: $this->name
"; echo "Работает в $this->company
"; > > $tom = new Employee("Tom", "Microsoft"); $tom -> displayInfo(); ?>

Здесь класс Employee добавляет новое свойство — $company , которое хранит компанию работника. Также класс Employee переопределил конструктор, в который пеередаются данные для имени и компании. А также переопределен метод displayInfo() . Соответственно для создания объекта класса Employee, теперь необходимо использовать переопределенный в классе Employee конструктор:

$tom = new Employee("Tom", "Microsoft");

Класс-наследник переопределяет конструктор родительского класса, то для создания объекта класса-наследника необходимо использовать переопределенный в нем конструктор.

И также изменится поведение метода displayInfo() , который кроме имени также выведет и компанию работника:

Имя: Tom Работает в Microsoft

Вызов функционала родительского класса

Если мы посмотрим на код класса-наследника Employee, то можем увидеть части кода, которые повторяют код класса Person. Например, установка имени в конструкторе:

$this->name = $name;

Также вывод имени работника в методе displayInfo() :

echo "Имя: $this->name
";

В обоих случаях речь идет об одной строке кода. Однако что, если конструктор Employee повторяет установку не одного, а десятка свойств. Соответственно что, если метод displayInfo в классе-наследнике повторяет горадо больше действий родительского класса. В этом случае горадо рациональнее не писать повторяющийся код в классе-наследнике, а вызвать в нем соответствующий функционал родительского класса.

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

Например, перепишем предыдущий пример:

name = $name; > function displayInfo() < echo "Имя: $this->name
"; > > class Employee extends Person < public $company; function __construct($name, $company) < parent::__construct($name); $this->company = $company; > function displayInfo() < parent::displayInfo(); echo "Работает в $this->company
"; > > $tom = new Employee("Tom", "Microsoft"); $tom -> displayInfo(); ?>

Теперь в конструкторе Employee вызывается конструктор базового класса:

parent::__construct($name);

В нем собственно и происходит установка имени. И подобным образом в методе displayInfo() вызывается реализация метода класса Person:

parent::displayInfo();

В итоге мы получим тот же самый результат.

Стоит отметить, что в реальности ключевое слово parent заменяет название класса. То есть мы также могли вызывать функционал родительского класса через имя этого класса:

class Employee extends Person < public $company; function __construct($name, $company) < Person::__construct($name); $this->company = $company; > function displayInfo() < Person::displayInfo(); echo "Работает в $this->company
"; > >

Оператор instanceof

Оператор instanceof позволяет проверить принадлежность объекта определенному классу. Слева от оператора располагается объект, который надо проверить, а справа — название класса. И если объект представляет класс, то оператор возвращает true . Например:

class Person < public $name; function __construct($name) < $this->name = $name; > function displayInfo() < echo "Имя: $this->name
"; > > class Employee extends Person < public $company; function __construct($name, $company) < Person::__construct($name); $this->company = $company; > function displayInfo() < Person::displayInfo(); echo "Работает в $this->company
"; > > class Manager<> $tom = new Employee("Tom", "Microsoft"); $tom instanceof Employee; // true $tom instanceof Person; // true $tom instanceof Manager; // false

Здесь переменная $tom представляет класс Employee , поэтому $tom instanceof Employee возвращает true .

Так как класс Employee унаследован от Person, то переменная $tom также представляет класс Person (работник также является человеком).

А вот класс Manager переменная $tom не преддставляет, поэтому выражение $tom instanceof Manager возвращает false .

Запрет наследования и оператор final

В примере выше метод displayInfo() переопределялся классом-наследником. Однако иногда возникают ситуации, когда надо запретить переопределение методов. Для этого в классе-родителе надо указать методы с модификатором final :

class Person < public $name; function __construct($name) < $this->name = $name; > final function displayInfo() < echo "Имя: $this->name
"; > > class Employee extends Person < public $company; function __construct($name, $company) < Person::__construct($name); $this->company = $company; > function displayEmployeeInfo() < Person::displayInfo(); echo "Работает в $this->company
"; > > $tom = new Employee("Tom", "Microsoft"); $tom -> displayEmployeeInfo();

В этом случае во всех классах-наследниках от класса Person мы уже не сможем определить метод с таким же именем. Поэтому в данном случае в классе Employee определен новый метод — displayEmployeeInfo.

Также мы можем вообще запретить наследование от класса. Для этого данный класс надо определить с модификатором final :

final class Person < public $name; function __construct($name) < $this->name = $name; > final function displayInfo() < echo "Имя: $this->name
"; > >

Теперь мы не сможем унаследовать класс Employee (да и никакой другой класс) от класса Person.

is_subclass_of

Функция проверяет, принадлежит ли объект или класс object_or_class к потомкам класса class , или реализует ли объект или класс, или родители объекта или класса, интерфейс.

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

Имя класса или экземпляр объекта. Если класс не найден, ошибка не будет выдана.

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

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

Функция возвращает true , если объект или класс object_or_class принадлежит к потомкам класса class , или если объект или класс, или предок объекта или класса, реализует интерфейс, иначе false .

Примеры

Пример #1 Пример использования функции is_subclass_of()

// Объявляем класс
class WidgetFactory
var $oink = ‘moo’ ;
>

// Объявляем наследника
class WidgetFactory_Child extends WidgetFactory
var $oink = ‘oink’ ;
>

// Создаём новые объекты
$WF = new WidgetFactory ();
$WFC = new WidgetFactory_Child ();

if ( is_subclass_of ( $WFC , ‘WidgetFactory’ )) echo «Да, объект \$WFC наследует класс WidgetFactory\n» ;
> else echo «Нет, объект \$WFC не наследует класс WidgetFactory\n» ;
>

if ( is_subclass_of ( $WF , ‘WidgetFactory’ )) echo «Да, объект \$WF наследует класс WidgetFactory\n» ;
> else echo «Нет, объект \$WF не наследует класс WidgetFactory\n» ;
>

if ( is_subclass_of ( ‘WidgetFactory_Child’ , ‘WidgetFactory’ )) echo «Да, класс WidgetFactory_Child наследует класс WidgetFactory\n» ;
> else echo «Нет, класс WidgetFactory_Child не наследует класс WidgetFactory\n» ;
>

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

Да, объект $WFC наследует класс WidgetFactory Нет, объект $WF не наследует класс WidgetFactory Да, класс WidgetFactory_Child наследует класс WidgetFactory

Пример #2 Пример использования функции is_subclass_of() с интерфейсами

// Определяем интерфейс
interface MyInterface
public function MyFunction ();
>

// Определяем реализацию интерфейса классом
class MyClass implements MyInterface
public function MyFunction ()
return «Класс MyClass реализует интерфейс MyInterface!» ;
>
>

// Создаём объект
$my_object = new MyClass ;

// Код ниже работает с PHP 5.3.7

// Проверяем экземпляр объекта класса
if ( is_subclass_of ( $my_object , ‘MyInterface’ )) echo «Да, тип экземпляра объекта \$my_object наследует тип интерфейса MyInterface\n» ;
> else echo «Нет, тип экземпляра объекта \$my_object не наследует тип интерфейса MyInterface\n» ;
>

// Проверяем строку — имя класса
if ( is_subclass_of ( ‘MyClass’ , ‘MyInterface’ )) echo «Да, класс-тип MyClass наследует класс-тип MyInterface\n» ;
> else echo «Нет, класс-тип MyClass не наследует класс-тип MyInterface\n» ;
>

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

Да, тип экземпляра объекта $my_object наследует тип интерфейса MyInterface Да, класс-тип MyClass наследует класс-тип MyInterface

Примечания

Замечание:

Вызов этой функции будет использовать все зарегистрированные функции автозагрузки, если класс ещё не известен.

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

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

Как получить namespase класса который вызвал метод в другом классе?

Ох — зачем нужно, если честно очень долго объяснять, у меня есть модель в проекте, и она должна очень хитро обновлять свои статусы. Во общем что бы понять почему именно так надо погружаться в задачу, что выходит за рамки этого вопроса.

11 авг 2021 в 9:45

1 ответ 1

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

 $callerClass = $trace[2]['class']; $callerNamespace = substr($callerClass, 0, strrpos($callerClass, '\\')) ; return $callerNamespace; > namespace App\B\ClassB; class B < public function call()< print_r(\App\callerNamespace()); echo PHP_EOL; return 1; >> namespace App\A\ClassA; use App\B\ClassB\B; class A< public function use_f()< $b = new B(); print_r("call from another class" . PHP_EOL); $b->call(); > > $a = new A(); $a->use_f(); $b = new \App\B\ClassB\B(); print_r("call outside another class" . PHP_EOL); $b->call(); ?> 

Как видите если вызвать B::call() не из другого класса, то функция callerNamespace() вернёт null.

Если интересно моё мнение: Если у вас возникает необходимость менять поведение метода в зависимости от того откуда он был вызван — скорее всего у вас проблема в архитектуре. Лучше перепишите ваш код так чтобы использовать разные сервисы в разных неймспейсах, чтобы поведение было более явным.

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() — Проверяет, принадлежит ли объект к потомкам класса, или реализует ли объект или родители объекта интерфейс

Improve This Page

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»

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

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

13 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.

6 years ago

When calling dynamic method statically in php 5.6 (under 7) it allows it, but it doesnt work, it incorrectly evaluates class that called our subject class, therefore containing method must be static.

15 years ago

It is possible to write a completely self-contained Singleton base class in PHP 5.3 using get_called_class.

abstract class Singleton

protected function __construct () <
>

final public static function getInstance () <
static $aoInstance = array();

if (! isset ( $aoInstance [ $calledClassName ])) <
$aoInstance [ $calledClassName ] = new $calledClassName ();
>

return $aoInstance [ $calledClassName ];
>

final private function __clone () <
>
>

class DatabaseConnection extends Singleton

protected function __construct () <
// @todo Connect to the database
>

public function __destruct () <
// @todo Drop the connection to the database
>
>

$oDbConn = new DatabaseConnection (); // Fatal error

$oDbConn = DatabaseConnection :: getInstance (); // Returns single instance
?>

14 years ago

If you call a static getInstance() function to create a instance of a class from another class, this function have to be static, if it is not static the original name of the caller class and not of the current class get returned.

class a function getXName () return x :: getClassName ();
>
function getXStaticName () return x :: getStaticClassName ();
>

class b extends a >

class x public function getClassName () return get_called_class ();
>
public static function getStaticClassName () return get_called_class ();
>
>

echo $a -> getXName (); // will return «a»
echo $b -> getXName (); // will return «b»

echo $a -> getXStaticName (); // will return «x»
echo $b -> getXStaticName (); // will return «x»

14 years ago

Beware that this does not behave as expected if your method is not declared as static! For example:

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

public function testTwo () var_dump ( get_called_class ());
>
>

class bar extends foo >

class abc function test () foo :: test ();
bar :: test ();
>

function testTwo () foo :: testTwo ();
bar :: testTwo ();
>
>

echo «basic\n» ;
foo :: test ();
bar :: test ();

echo «basic without static declaration\n» ;
foo :: testTwo ();
bar :: testTwo ();

echo «in a class\n» ;
$abc = new abc ();
$abc -> test ();

echo «in a class without static declaration\n» ;
$abc -> testTwo ();

basic
string ‘foo’
string ‘bar’

basic without static declaration
string ‘foo’
string ‘bar’

in a class
string ‘foo’
string ‘bar’

in a class without static declaration
string ‘abc’
string ‘abc’

15 years ago

Here’s a simple way of getting the inheritance tree of a class, no matter which class the function was actually defined in. Will work as a static function method too.

class A <
public function get_class_tree () <
$cur_class = get_called_class ();
do <
echo $cur_class ;
>
while( $cur_class = get_parent_class ( $cur_class ));
>
>

$foo = new C ();
$foo -> get_class_tree ();

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

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