PHP debug_backtrace в производственном коде, чтобы получить информацию о вызывающем методе?

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

В debug_backtrace есть ошибка: прочтите stackoverflow.com/q/4581969/632951

Pacerier 02.08.2013 16:21
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
28
1
14 142
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Is there a compelling reason to not use debug_backtrace for the sole purpose of determining the calling method's class, name, and parameter list?

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

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

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

Sydius 06.12.2008 23:27

Честно говоря, я не знаю. Я не вижу способа справиться с этим по-другому, так что это может быть подходящим случаем для такого использования.

Konrad Rudolph 07.12.2008 00:20

@Mawg Да. Обработка ошибок и отладка часто очень похожи. А если эту функцию вообще не следует использовать, зачем она существует?

Konrad Rudolph 06.06.2011 12:30

debug_backtrace - одна из функций обработки ошибок PHP. Руководство побуждает пользователей определять свои собственные правила обработки ошибок, а также изменять способ регистрации ошибок. Это позволяет вам изменять и улучшать отчеты об ошибках в соответствии с вашими потребностями. Это также означает, что снижение производительности от использования этих функций незначительно.

Я думаю, что ты делаешь нормально.

Ответ принят как подходящий

Это действительно кажется немного грязным, но, как было хорошо задокументировано, высказано и забито до смерти в других местах, PHP не является системой, разработанной для элегантности.

Одна очень запутанная причина, по которой нет использует debug_backtrace для логики приложения, заключается в том, что какой-то будущий разработчик, работающий над PHP, может решить, что «это просто функция отладки, производительность не имеет значения».

Если вас интересует «лучший» способ сделать это, вы, вероятно, могли бы использовать Магические константы PHP для передачи вызывающего метода и имени класса, а затем использовать объект ReflectionMethod для извлечения любой другой необходимой информации.

Я лучше заключил в кавычки, потому что, хотя это было бы чище и правильнее, накладные расходы на создание экземпляра объекта Reflection май были бы больше, чем при использовании функции debug_backtrace.

Да, я тогда не знал о КЛАСС или НАЗНАЧЕНИЕ. Или объект «Отражение». Думаю, если бы я сделал это снова, я бы сделал это вместо этого.

Sydius 07.12.2008 04:17

Еще одна вещь, которую следует учитывать, - это то, как часто вам это нужно: поддержание аналогичной информации в PHP-коде добавит значительных циклов к каждому запросу, поэтому случайный debug_stacktrace, безусловно, будет предпочтительнее. В целом, тем не менее, я согласен с Конрадом: помимо отладки / регистрации / необычных потребностей дизайн не должен этого требовать.

Steve Clay 28.05.2010 06:06

Вы сказали в комментарии

The callee's task is to call the same method that called it on a different computer. It's to avoid having a different API function for every possible source, which reduced the amount of code in the system considerably. Is it still bad

Итак, вы хотите сделать следующее:

  • Функция foo () вызывает
  • Функция отражающий (), которая выполняет обратную трассировку отладки и запрашивает
  • http://example.com/REST/фу

Предполагая, конечно, что вы используете HTTP-запросы для отключения удаленного вызова.

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

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

  • Функция foo () вызывает
  • Функция отражающий (__ CLASS__, __FUNCTION__), которая запрашивает
  • http://example.com/REST/фу

Я не знал о КЛАСС и НАЗНАЧЕНИЕ, когда впервые написал это, иначе я бы, вероятно, знал. Я хотел что-то легкое для копирования / вставки (и постоянное). Я действительно хочу, чтобы в PHP были макросы (настолько плохи, насколько ими можно злоупотреблять).

Sydius 07.12.2008 04:16

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

/*Called from /var/www/micimacko.php at line 28*/ SELECT count(*) FROM rofibeka;

Остается вопрос. Насчет производительности / надежности.

Функция trigger_error () делает именно то, что Вы описали, плюс сохраняет ошибку в журнал ошибок Apache. Я использую trigger_error (mysql_error ()), чтобы сохранять все ошибки в журнал или отображать их на экране (в зависимости от того, нахожусь ли я на производственном сервере или на сервере разработки).

Rauni Lillemets 19.08.2011 14:47

Правильный ответ - это полностью В ПОРЯДКЕ. Алан указывает на неэлегантность PHP, поэтому я не буду повторять его аргументы. Причина (не бояться) использования debug_backtrace в коде времени выполнения заключается в том, что PHP в основном является контекстно-свободным языком. Каждая функция не знает и не может знать «намерение» вызывающего без использования волшебных имен функций (например, в классе - например, __toString ()) с приведениями. Давайте рассмотрим случай, когда у вас есть класс, в котором (в методе) вы хотите предоставить доступ к свойствам вызывающего (внешнего) класса. Это действительно беспорядочно и подвержено ошибкам при передаче ($ this) через API функции. (Особенно, если вы хотите использовать array_map или call_user_func_array.)

например

<?
class a {
 public $v = 'xyz';
 function __construct($x,$y)
 {
   $b = new b();
 }
}
class b {
 function __construct()
 {
   $start = microtime();
   $x = debug_backtrace();
   $end = microtime();
   echo ($end-$start) . "\n";
   print_r($x);
   $obj = $x[1]['object'];
   print_r($obj);
 }
}
$a = new a(1,2);
?>

Debug_backtrace предоставит вам доступ к контексту класса a в __construct b. Теперь вы можете передавать некоторые переменные состояния из текущего класса, не передавая $ this, не пытаясь угадать его по именам классов или путать его, помещая в глобальные переменные.

Для тех, кто интересуется временем, микровремя было 2.7E-5. Достаточно быстро. Только не откладывайте это на некоторое время (1).

Я сделал еще один тест производительности метода debug_backtrace. Чтобы имитировать реальные стеки, я определил несколько классов, которые случайным образом вызывают методы другого класса - с указанной ГЛУБИНОЙ:

<?php

const DEPTH = 30;
const BACKTRACE = false;

class TestClass
{
    public $a;
    public $b;

    public function __construct()
    {
        $foo = new Foo();
        $bar = new Bar();
        $alice = new Alice();

        $alice->a = $foo;
        $bar->a = $foo;

        $foo->a = $bar;
        $alice->b = $bar;

        $foo->b = $alice;
        $bar->b = $alice;

        $this->a = $foo;
        $this->b = $bar;
    }

    public function method($depth)
    {
        BACKTRACE ? debug_backtrace() : null;
        $obj = mt_rand(0,1) === 1 ? $this->a : $this->b;

        if ($depth > DEPTH) {
            return;
        }
        $obj->method($depth+1);

    }
}

class Foo
{
    public $a;
    public $b;

    public function method($depth)
    {
        BACKTRACE ? debug_backtrace() : null;

        $obj = mt_rand(0,1) === 1 ? $this->a : $this->b;

        if ($depth > DEPTH) {
            return;
        }
        $obj->method($depth+1);
    }
}

class Bar
{
    public $a;
    public $b;
    public function method($depth)
    {
        BACKTRACE ? debug_backtrace() : null;
        $obj = mt_rand(0,1) === 1 ? $this->a : $this->b;

        if ($depth > DEPTH) {
            return;
        }
        $obj->method($depth+1);
    }
}

class Alice
{
    public $a;
    public $b;

    public function method($depth)
    {
        BACKTRACE ? debug_backtrace() : null;

        $obj = mt_rand(0,1) === 1 ? $this->a : $this->b;

        if ($depth > DEPTH) {
            return;
        }

        $obj->method($depth+1);
    }
}


$test = new TestClass();

$startWhole = microtime(true);
for($i = 0; $i < 10000;$i++) {
    $start = microtime(true);
    $test->method(0);
    $end = microtime(true);
}
$endWhole = microtime(true);
$total = $endWhole - $startWhole;

echo 'total time: ' . $total . "s\n";

Результат:

Performance (10.000 iterations / stack depth 30 / PHP 7.2):

with debug_backtrace - total time: 0.86011600494385s
without:             - total time: 0.043321847915649s 

использование debug_backtrace делает этот код в 20 раз медленнее.

Другие вопросы по теме