如何从生产 PHP 代码中获取正确的调试上下文?

要求

我们在网络服务器上运行生产 PHP 代码。在某些情况下,我们希望使用上下文信息来丰富调试输出(例如到 error.log)。上下文可以具有任意字段和结构。

我们的目标是找到一个通用的调试生成函数,它在任何极端情况下都不会产生警告。如果输出只是部分是可以接受的。

TL; 博士

所有三个 PHP 标准函数都会在特定上下文中导致警告:

  • print_rvar_dump无法处理连接关闭的 mysqli 对象

  • var_export无法处理递归

有没有办法将任意对象的上下文作为人类可读的字符串返回?

测试用例

// Dealing with recursion:

$recObj = new stdClass();

$recObj->recursion = $recObj;


print_r   ($recObj);  // works

var_export($recObj);  // throws: "Warning: var_export does not handle circular references"

var_dump  ($recObj);  // works



// dealing with mysqli

$mysqli = mysqli_connect('mysql', 'root', 'myPass', 'mysql');

print_r   ($mysqli);  // works

var_export($mysqli);  // works as in "does not throw warnings" but all values are null

var_dump  ($mysqli);  // works


// Try again with closed connection

mysqli_close($mysqli);

print_r   ($mysqli);  // throws: "Warning: print_r(): Couldn't fetch mysqli"

var_export($mysqli);  // works (again all values are null)

var_dump  ($mysqli);  // throws: Warning: var_dump(): Couldn't fetch mysqli

根据关闭的 mysqli 连接相关性:如果您在错误处理程序或注册的关闭函数中进行上下文打印(这是一个很好的位置),一旦您到达该连接,mysqli 对象将已经自动关闭连接处理程序。

如您所见,没有任何内置输出方法能够返回您抛出的任何上下文。

考虑的选项

  1. 可以使用@notation 来抑制警告。但是,注册的错误处理程序和关闭函数仍然会被错误调用,并且需要自定义逻辑来忽略该特定错误。这可能会隐藏真正的错误,并且如果处理像 sentry.io 这样的 3rd 方错误跟踪系统也会变得非常烦人

  2. serialize()函数在任何情况下都不会产生警告,但缺乏人类可读性。

  3. json_encode()函数可以比序列化更具可读性,但它在递归测试用例中不返回任何内容......


至尊宝的传说
浏览 191回答 1
1回答

不负相思意

我没有找到一个内置的打印功能,它在包含具有关闭连接的 mysqli 对象时不会导致错误/警告(我实际上将其归类为错误/不需要的行为)。我们结束了加入的Symfony Vardumper通过composer require symfony/var-dumper并编写一个小辅助函数来显示来自 cli 脚本或浏览器的正确和漂亮的输出:use Symfony\Component\VarDumper\Cloner\VarCloner;use Symfony\Component\VarDumper\Dumper\CliDumper;use Symfony\Component\VarDumper\Dumper\HtmlDumper;class Debug {    /**     * Method provides a function which can handle all our corner-cases for producing      * debug output.     *     * The corner cases are:     * - objects with recursion     * - mysqli references (also to closed connections in error handling)     *     * The returned result will be:     *  - formatted for CLI if the script is run from cli     *  - HTML formatted otherwise     *      - The HTML formatted output is collapsed by default. Use CTRL-left click to      *        expand/collapse all children     *  - You can force html|cli formatting using the optional third parameter     *     * Uses the Symfony VarDumper composer module.     *     * @see https://github.com/symfony/var-dumper     * @see https://stackoverflow.com/questions/57520457/how-to-get-proper-debug-context-from-production-php-code-print-r-vs-var-export     * @param mixed       $val    - variable to be dumped     * @param bool        $return - if true, will return the result as string     * @param string|null $format null|cli|html for forcing output format     * @return bool|string     */    public static function varDump($val, $return = false, $format = null) {        if (is_null($format)) {            $format = php_sapi_name() == 'cli' ? 'cli' : 'html';        }        $cloner = new VarCloner();        if ($format === 'cli') {            $dumper = new CliDumper();        } else {            $dumper = new HtmlDumper();        }        $output = fopen('php://memory', 'r+b');        $dumper->dump($cloner->cloneVar($val), $output);        $res = stream_get_contents($output, -1, 0);        if ($return) {            return $res;        } else {            echo $res;            return true;        }    }}那个方法可以处理我传递给它的所有输入而没有错误或警告CLI 和 HTML 的格式都很好将结果作为字符串返回,以便将其转发到外部错误跟踪系统,如哨兵所以它勾选了我在最初问题中要求的所有方框。感谢@BlackXero 正确理解问题并将我指向正确的方向。
打开App,查看更多内容
随时随地看视频慕课网APP