PHP json_encode a debug_backtrace() 与资源类型

发布于 2024-12-19 17:39:45 字数 1379 浏览 1 评论 0原文

目前,我有一个记录器,它将错误和回溯记录在一起。 记录器通过 json_encode() 将回溯序列化为 JSON。

让我们看一些假设的代码...

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

Currently, I have a logger which logs errors together with a backtrace.
The logger serializes the backtrace to JSON via json_encode().

Let's look at some hypothetical code...

<?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
?>

If you run the code above, we will see something like:

Warning: json_encode() [function.json-encode]: type is unsupported, encoded as null in /code/ch6gVw on line 5
[{"file":"/code/ch6gVw","line":8,"function":"test","args":[null]}]

We can notice two things going on here:

  1. The logger itself is causing a warning! Bad bad bad!
  2. The logged data tells us we passed a null to the function?!?!

So, my proposed solution is something like:

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

The result would look like Resource id #1 (gd)


This, however, may cause some grave issues.

  1. We need to somehow track which arrays we looped through so as to avoid ending up in infinite loops with arrays referencing themselves ($GLOBALS tend to cause this mess).
  2. We would also have to convert resources of object properties, but objects, unlike arrays, are not a copy of the original thing, hence changing the property changes the live object. On the other hand, how safe is it to clone() the object?
  3. Won't such a loop severely slow down the server (backtraces tend to be large, no)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不爱素颜 2024-12-26 17:39:45

我最终得到了以下函数:

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( ),邀请破坏)。

I ended up with the following function:

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;
}

You can see it in action here. However, I'm not convinced:

  • It is quite slow (iterating over lots of data)
  • It is quite memory intensive (data needs to be copied to not mess the original)
  • It is not safe in case where arrays/objects reference themselves
    • Example: $a = array(); $a['ref'] = &$a; (PHP does this to some internal variables)
  • I'm concerned that cloning objects may have some serious side-effects (consider the magic method __clone(), an invitation to wreck havoc).
一个人的旅程 2024-12-26 17:39:45

那么您正在尝试将回溯存储为一种数据结构,以便稍后可以用来漂亮地打印结果?

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

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

So you are trying to store the backtrace as a data structure that can be used to pretty-print the results later on?

If that isn't needed I'd just store $result = print_r(debug_backtrace(), true) and be done with it.

If not my first shot would be something like:

<?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;
}   

It's just a rough sketch but I'm not aware of any project that stores backtracks for later inspection in a non textual or already processed format and looking around the mature frameworks didn't bring anything up

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文