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






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 для каждого возможного источника, что значительно уменьшило объем кода в системе. Это все еще плохо?
Честно говоря, я не знаю. Я не вижу способа справиться с этим по-другому, так что это может быть подходящим случаем для такого использования.
@Mawg Да. Обработка ошибок и отладка часто очень похожи. А если эту функцию вообще не следует использовать, зачем она существует?
debug_backtrace - одна из функций обработки ошибок PHP. Руководство побуждает пользователей определять свои собственные правила обработки ошибок, а также изменять способ регистрации ошибок. Это позволяет вам изменять и улучшать отчеты об ошибках в соответствии с вашими потребностями. Это также означает, что снижение производительности от использования этих функций незначительно.
Я думаю, что ты делаешь нормально.
Это действительно кажется немного грязным, но, как было хорошо задокументировано, высказано и забито до смерти в других местах, PHP не является системой, разработанной для элегантности.
Одна очень запутанная причина, по которой нет использует debug_backtrace для логики приложения, заключается в том, что какой-то будущий разработчик, работающий над PHP, может решить, что «это просто функция отладки, производительность не имеет значения».
Если вас интересует «лучший» способ сделать это, вы, вероятно, могли бы использовать Магические константы PHP для передачи вызывающего метода и имени класса, а затем использовать объект ReflectionMethod для извлечения любой другой необходимой информации.
Я лучше заключил в кавычки, потому что, хотя это было бы чище и правильнее, накладные расходы на создание экземпляра объекта Reflection май были бы больше, чем при использовании функции debug_backtrace.
Да, я тогда не знал о КЛАСС или НАЗНАЧЕНИЕ. Или объект «Отражение». Думаю, если бы я сделал это снова, я бы сделал это вместо этого.
Еще одна вещь, которую следует учитывать, - это то, как часто вам это нужно: поддержание аналогичной информации в PHP-коде добавит значительных циклов к каждому запросу, поэтому случайный debug_stacktrace, безусловно, будет предпочтительнее. В целом, тем не менее, я согласен с Конрадом: помимо отладки / регистрации / необычных потребностей дизайн не должен этого требовать.
Вы сказали в комментарии
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
Итак, вы хотите сделать следующее:
Предполагая, конечно, что вы используете HTTP-запросы для отключения удаленного вызова.
Это немного странная установка. Если вы создаете систему с нуля, я бы посоветовал попробовать ее обойти. Если вы вставляете его в устаревшую систему, я полагаю, я понимаю.
Я предлагаю вам всегда быть более откровенным, когда это возможно. Использование вами магического самоанализа стека может сэкономить вам немного времени на кодирование, но для другого разработчика ваш код будет совершенно непонятным. Если вы предложите передать имя класса и функции функции, которая ранее выполняла отражение. Тогда не будет двусмысленности в том, что происходит.
Я не знал о КЛАСС и НАЗНАЧЕНИЕ, когда впервые написал это, иначе я бы, вероятно, знал. Я хотел что-то легкое для копирования / вставки (и постоянное). Я действительно хочу, чтобы в PHP были макросы (настолько плохи, насколько ими можно злоупотреблять).
Я думаю об использовании debug_backtrace для отладки операторов mysql. Когда у вас есть такой заголовок в начале каждого запроса внутри журналов базы данных, намного проще определить ошибочные или медленные запросы:
/*Called from /var/www/micimacko.php at line 28*/ SELECT count(*) FROM rofibeka;
Остается вопрос. Насчет производительности / надежности.
Функция trigger_error () делает именно то, что Вы описали, плюс сохраняет ошибку в журнал ошибок Apache. Я использую trigger_error (mysql_error ()), чтобы сохранять все ошибки в журнал или отображать их на экране (в зависимости от того, нахожусь ли я на производственном сервере или на сервере разработки).
Правильный ответ - это полностью В ПОРЯДКЕ. Алан указывает на неэлегантность 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 раз медленнее.
В debug_backtrace есть ошибка: прочтите stackoverflow.com/q/4581969/632951