Intereting Posts
Как сломать строку заглавными буквами с помощью PHP? функция возвращается только один раз, почему? Запуск приложения командной строки из PHP в качестве конкретного пользователя Передайте выбранные данные о вариациях продукта в форму запроса контактной формы 7 laravel load view из имени папки с фактической точкой Что такое регулярное выражение для решения этой проблемы? Как и где сохранять загруженные файлы с помощью ng-потока? Как я могу использовать API для получения данных quickbooks без браузера OAUTH? Как получить int вместо строки из формы? Получить корневую запись DNS с сервера php; получить доменное имя без www, ect сопоставить шаблон url в php с использованием регулярного выражения Загрузить в произвольный файл .html с помощью PHP? Что означают два двоеточия в PHP? Должны ли зависимости автоматически удаляться с диска после установки / обновления с помощью Composer? PHP «Истек срок действия документа» после использования кнопки «Назад»

Узнайте, какой класс называется методом в другом классе

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

Exmaple:

class Foo { public function __construct() { $bar = new Bar(); $bar->test(); } } class Bar { public function test() { } } $foo = new Foo(); 

Будет ли у меня способ узнать, что метод теста вызывается из объекта foo?

вы можете использовать debug_backtrace , немного похожее на это:
BTW, взгляните на комментарии на странице руководства: есть некоторые полезные функции и рекомендации 😉

 class Foo { public function __construct() { $bar = new Bar(); $bar->test(); } } class Bar { public function test() { $trace = debug_backtrace(); if (isset($trace[1])) { // $trace[0] is ourself // $trace[1] is our caller // and so on... var_dump($trace[1]); echo "called by {$trace[1]['class']} :: {$trace[1]['function']}"; } } } $foo = new Foo(); 

Результат var_dump выводит:

 array 'file' => string '/home/squale/developpement/tests/temp/temp.php' (length=46) 'line' => int 29 'function' => string '__construct' (length=11) 'class' => string 'Foo' (length=3) 'object' => object(Foo)[1] 'type' => string '->' (length=2) 'args' => array empty 

и echo :

 called by Foo :: __construct 

Но, как ни приятно, я не уверен, что он должен использоваться как «нормальная вещь» в вашем приложении … Кажется странным, на самом деле: с хорошим дизайном, метод не должен знать, что его называют , по моему мнению.

Вот одно линейное решение

 list(, $caller) = debug_backtrace(false, 2); 

Начиная с PHP7 это не будет работать на основе документов: http://php.net/manual/en/function.list.php, поскольку мы не можем иметь пустые свойства, вот небольшое обновление:

 list($childClass, $caller) = debug_backtrace(false, 2); 

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

например

 class Foo { public function __construct() { $bar = new Bar(); $bar->test($this); } } class Bar { public function test() { } } $foo = new Foo(); 

Я получил эту идею из книги «Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения» Эриха Гамма и др. На стр. 278 в дискуссии о структурной структуре «Посредник».

Точка шаблона заключается в уменьшении количества связей «много-ко-многим» между кучей объектов / классов. Вы создаете класс посредника, который все эти классы рассматривают как концентратор. Таким образом, классы не должны знать друг о друге. Медиатор обрабатывает взаимодействия. Чтобы медиатор был проинформирован об изменениях в классах, которые он отслеживает, они могут передавать себя в качестве аргументов, или посредник может быть реализован с использованием шаблона «Наблюдатель».

Вероятно, вы можете добиться этого с помощью отладочной обратной линии, хотя это кажется хакерским.

Ваш альтернативный вариант – передать параметр этому классу и сообщить ему, откуда он вызывается, когда вы создаете экземпляр класса из другого.

По крайней мере, вы можете использовать debug_backtrace и проанализировать это, чтобы найти вызывающий метод.

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

@Pascal MARTIN: Да, в обычных заявлениях это, вероятно, не нужно. Но иногда это может быть полезно. Рассмотрим пример из моего собственного приложения:

Существует подкласс Controller, который может использовать объект Template для подготовки своего вывода. У каждого шаблона есть имя, на которое нужно ссылаться. Когда контроллеру нужен шаблон, он запрашивает у него TemplateManager, указывая это имя как параметр. Но может быть много файлов шаблонов с этим именем для разных контроллеров. Контроллеры используются в качестве плагинов и могут быть написаны разными пользователями, поэтому имена, используемые ими, не могут контролироваться, чтобы не сталкиваться друг с другом. Пространства имен для шаблонов необходимы. Поэтому TemplateManager, который является фабрикой для объектов Template, нуждается в имени шаблона и имени пространства имен, чтобы найти правильный исходный файл шаблона. Это пространство имен связано с именем класса конкретного контроллера.

Но в большинстве случаев каждый контроллер будет использовать шаблоны из собственного пространства имен и только в редких случаях из других пространств имен. Таким образом, определение пространства имен в каждом вызове TemplateManager :: getTemplate () каждый раз будет бесполезным. Лучше, если пространство имен является необязательным и по умолчанию используется … контроллер, который вызывает TemplateManager :: getTemplate ()! И здесь хорошее место для знакомства с вызывающим.

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

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

Эта функция выполняет работу без debug_backtrace:

 /* usage : some code... getRealCallClass(__FUNCTION__); some code... */ function getRealCallClass($functionName) //Parameter value must always be __FUNCTION__ { try { throw new exception(); } catch(exception $e) { $trace = $e->getTrace(); $bInfunction = false; foreach($trace as $trace_piece) { if ($trace_piece['function'] == $functionName) { if (!$bInfunction) $bInfunction = true; } elseif($bInfunction) //found !!! { return $trace_piece['class']; } } } }