PHP json_encode debug_backtrace () с типами ресурсов - PullRequest
3 голосов
/ 06 декабря 2011

В настоящее время у меня есть регистратор, который регистрирует ошибки вместе с обратным следом. Регистратор сериализует обратную трассировку в JSON через json_encode().

Давайте посмотрим на некоторый гипотетический код ...

<?php
    error_reporting(-1);                          // show all errors
    function test($b){
        echo json_encode(debug_backtrace());      // take a backtrace snapshot
    }
    $c = imagecreate(50,50);                      // create a resource...
    test($c);                                     // ...and pass to function
?>

Если вы запустите код выше , мы увидим что-то вроде:

Предупреждение: json_encode () [function.json-encode]: тип не поддерживается, кодируется как ноль в / code / ch6gVw в строке 5 [{ "Файл": "/ код / ​​ch6gVw", "линия": 8, "функция": "Тест", "арг": [пустой]}]

Здесь можно заметить две вещи:

  1. Сам логгер вызывает предупреждение! Плохо, плохо, плохо!
  2. Зарегистрированные данные говорят нам, что мы передали нуль в функцию?!?!

Итак, мое предлагаемое решение выглядит примерно так:

foreach($trace as $i=>$v)
    if(is_resource($v))
        $trace[$i] = (string)$v.' ('.get_resource_type($v).')';

Результат будет выглядеть как Resource id #1 (gd)


Это, однако, может вызвать серьезные проблемы.

  1. Нам нужно как-то отследить, какие массивы мы перебрали, чтобы избежать попадания в бесконечные циклы с ссылками на сами массивы ($GLOBALS имеет тенденцию вызывать этот беспорядок).
  2. Нам также пришлось бы преобразовывать ресурсы свойств объекта, но объекты, в отличие от массивов, не являются копией оригинальной вещи, поэтому изменение свойства приводит к изменению живого объекта. С другой стороны, насколько это безопасно для clone() объекта?
  3. Не приведет ли такой цикл к значительному замедлению работы сервера (следы, как правило, большие, нет)?

Ответы [ 2 ]

2 голосов
/ 06 декабря 2011

Я получил следующую функцию:

function clean_trace($branch){
    if(is_object($branch)){
        // object
        $props = array();
        $branch = clone($branch); // doesn't clone cause some issues?
        foreach($props as $k=>$v)
            $branch->$k = clean_trace($v);
    }elseif(is_array($branch)){
        // array
        foreach($branch as $k=>$v)
            $branch[$k] = clean_trace($v);
    }elseif(is_resource($branch)){
        // resource
        $branch = (string)$branch.' ('.get_resource_type($branch).')';
    }elseif(is_string($branch)){
        // string (ensure it is UTF-8, see: https://bugs.php.net/bug.php?id=47130)
        $branch = utf8_encode($branch);
    }
    // other (hopefully serializable) stuff
    return $branch;
}

Вы можете увидеть это в действии здесь . Тем не менее, Я не уверен, :

  • Это довольно медленно (перебирает много данных)
  • Это довольно много памяти (данные должны быть скопированы, чтобы не испортить оригинал)
  • Это небезопасно в случае, когда массивы / объекты ссылаются на себя
    • Пример: $a = array(); $a['ref'] = &$a; (PHP делает это с некоторыми внутренними переменными)
  • Я обеспокоен тем, что клонирование объектов может иметь серьезные побочные эффекты (рассмотрим магический метод __clone(), приглашение разрушить хаос).
1 голос
/ 14 декабря 2011

То есть вы пытаетесь сохранить обратную трассировку в виде структуры данных, которую можно использовать для последующей распечатки результатов?

Если это не нужно, я просто сохраню $result = print_r(debug_backtrace(), true) и получус этим покончено.

Если бы не мой первый снимок, это было бы что-то вроде:

<?php
error_reporting(-1);
function test($b){
    echo json_encode(clean(debug_backtrace()));
}   
$c = fopen("/tmp/foo", "w");
test($c);


function clean($trace) {
    array_walk_recursive($trace, function(&$element) {
        if(is_object(&$element)) {
            // work around unrealizable elements and preserve typing
            $element = array(get_class($element), (object)$element); 
        } else if(is_resource($element)) {
            $element = get_resource_type($element) . '#'  .(int)$element;
        }   
    }); 
    return $trace;
}   

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

...