Подтвердить что ты не робот

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

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

Exmaple:

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

class Bar
{
  public function test()
  {
  }
}
$foo = new Foo();

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

4b9b3361

Ответ 1

вы можете использовать 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

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

Ответ 2

Вот одно решение liner

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

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

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

Ответ 3

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

например.

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

class Bar
{
  public function test()
  {
  }
}
$foo = new Foo();

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

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

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

@Паскаль МАРТИН: Да, в обычных заявлениях это, вероятно, не нужно. Но иногда это может быть полезно. Рассмотрим пример из моего собственного приложения:

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

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

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

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

Ответ 7

Эта функция выполняет задание без 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'];
           }
      }
   }
}