3

目前,我有一个记录器,它记录错误和回溯。记录器通过 将回溯序列化为 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]:类型不受支持,在第 5 行的 /code/ch6gVw 中编码为 null [{"file":"/code/ch6gVw","line":8,"function" :"test","args":[null]}]

我们可以注意到这里发生了两件事:

  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. 这样的循环不会严重减慢服务器的速度(回溯往往很大,不是)?
4

2 回答 2

2

我最终得到了以下功能:

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(),一个破坏浩劫的邀请)。
于 2011-12-06T08:35:06.217 回答
1

因此,您正在尝试将回溯存储为可用于稍后漂亮打印结果的数据结构?

如果不需要,我只需存储$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;
}   

这只是一个粗略的草图,但我不知道有任何项目以非文本或已经处理的格式存储回溯以供以后检查,并且环顾成熟的框架并没有带来任何东西

于 2011-12-14T09:31:15.220 回答