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

时间:2016-08-02 09:43:39

标签: php

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

我希望看到类似的内容:

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

但是,当我致电debug_backtrace()并解析args值时,我无法使用方法gettype()is_resource()get_resource_type()因为总是说变量属于未知类型

  
      
  1. 配置> saveToFile(未知类型:资源ID#99)在config.php :: 456
  2. 中   
  3. config.php :: 123
  4. 中的Config-> backup('config.bak')   

用于解析args的代码是:

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中都没有找到任何相关内容。

系统:

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

1 个答案:

答案 0 :(得分:1)

所以问题是资源只有在打开时才能被识别为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);
}