无法从回溯(调用堆栈)中识别PHP资源


PHP resources cannot be identified from backtrace (call stack)

我正在编写PHP方法来漂亮地打印带有params的调用堆栈原因是它将被用作公共API的输出(在调试模式下),因此它不能显示所有内容,只能显示保存信息

我想看看这样的东西:

  1. Config.php中的Config->saveToFile(resource:file):456
  2. Config.php中的Config->backup('Config.bak'):123

但是,当我调用debug_backtrace()并解析args值时,我不能使用方法gettype()is_resource()get_resource_type(),因为它总是说变量是未知类型:

  1. Config.php中的Config->saveToFile(未知类型:Resource id#99):456
  2. Config.php中的Config->backup('Config.bak'):123

用于解析参数的代码为:

public static function getTrace() {
    $trace = debug_backtrace();
    $output = [];
    foreach ($trace as $call) {
        $name = $call['class'] . $call['type'] . $call['function']
        //actual code checks for various situations
        $args = [];
        foreach ($call['args'] as $arg) {
            $args[] = self::toString($arg);
        }
        $name .= '(' . join(', ', $args) . ')';
        $output[] = $name . ' in ' . basename($call['file']) . '::' . $call['line'];
    }
    return $output;
}
protected static function toString($mixed) {
    //process known types - arrays, objects, strings, etc.    
    //...
    if (is_resource($mixed)) {
        return 'resource: ' . get_resource_type($mixed);
    }
    return gettype($mixed) . ': ' . $mixed;
}

即使我使用debug_backtrace文档中列出的diz at ysagoon dot com的代码,该文档使用gettype()并检查resource,在我的情况下,它也会返回Config->saveToFile(Unknown)

当我在创建资源的代码中使用方法时,它会正确地返回其类型。

没有从回溯中识别资源是否有限制或原因?我应该在PHP配置中启用什么?我在PHP文档和Google中都没有找到任何关于这方面的内容。


系统:

  • 示例3.2.2
  • Apache/2.4.17(Win32)
  • PHP/5.6.15
  • Windows 10 Pro x64周年纪念版1607(10.0.14393)

所以问题是资源只能在打开时被标识为resource。关闭资源后,方法gettype()is_resource()get_resource_type()不再将其标识为resource,而是更改为unknown type

$f = fopen('tmp', 'w');
echo gettype($f); //= 'resource'
fclose($f);
echo gettype($f); //= 'Unknown type'

为了在回溯中打印关闭的资源,我创建了两种方法来在资源仍然打开时记住它们:

protected $resources = [];
public function traceResourceParams() {
    $trace = debug_backtrace();
    $args = [];
    foreach ($trace as $call) {
        foreach ($call['args'] as $arg) {
            if (is_resource($arg) && !array_key_exists(intval($arg), $this->resources)) {
                $this->resources[intval($arg)] = self::toString($arg);
            }
        }
    }
}
public function traceNamedResource($resource, $name) {
    if (is_resource($resource)) {
        $this->resources[intval($resource)] = '{' . get_resource_type($resource) . ': ' . $name . '}';
    }
}

并更新了我的toString方法来检查存储的资源:

protected static function toString($mixed) {
    //process known types - arrays, objects, strings, etc.    
    //...
    if (is_resource($mixed)) {
        return 'resource: ' . get_resource_type($mixed);
    }
    //closed resources does not evaluate as resource
    //but still convert to resource id using intval()
    //so we can match them to previously evaluated resources
    $val = intval($mixed);
    if ($val && array_key_exists($val, self::getInstance()->resources)) {
        return self::getInstance()->resources[$val];
    }
    return gettype($mixed) . ': ' . $mixed;
}

所以现在我可以在创建资源时存储它:

$f = fopen('tmp', 'w');
$debug->traceNamedResource($f, 'tmp');
fclose($f);

或者当它作为参数传递时:

protected function saveToFile($file) {
        $debug->traceResourceParams()
        //... work with file
        fclose($file);
}