[编程技巧] 命令行友好的 dd () 调试方法
每个Laravel开发者的调试工具中,都有一个最要而不起眼的 dd()
(dump and die)辅助函数,它可以输出变量内容并终止代码运行。在浏览器中, dd()
函数输出的是一个易读的树状结构,还带有可点击的小箭头按钮,用于展开或隐藏子嵌套结构。而在命令行终端,情况就大不相同了。
在进行大量测试时,我们会花费相当多的时间在终端中检查输出,而不是在浏览器。在对PHPUnit中失败的测试进行故障排除时,你通常会需要 dd()
函数输出数组、集合、类、Eloquent模型、API调用返回的JSON。 dd()
在命令行的输出和HTML一样是结构化的,但很多时候输出要么特别长,要么有很深的嵌套,导致你需要经常上下滚动去寻找你需要的信息。如果输出信息的长度超出了终端的缓冲区,那么将很难,甚至无法找到输出的顶部。
幸运的是,自定义 dd()
函数是简单的,我们可以通过定制来调整终端输出的内容,帮助你快速找到感兴趣的信息,而不至于耗尽你的耐心。只需一个帮助函数,你就可从定制前:
……到定制后:
……或者其他处于两者之间的效果。
有两种方法可以达成上述目标:
幸运的是,构建自己的定制版本的dd()
很简单,以帮助驯服您不必要的终端输出——帮助您快速找到您感兴趣的详细信息,而不会耗尽触控板(和您的耐心)。只需一个助手函数,您就可以做到从这样:
…到这样:
…或介于两者之间的任何东西。
有两种方法可以实现此目的:
选择之一:使用Symfony的VarDumper组件
从5.0版本开始,Laravel的 dd()
(和它的近亲 dump()
,不会终止程序运行) 一直依赖于Symfony的 VarDumper
组件。因此,增强dd()
的最简单方法是编写一个辅助函数,使你可以访问一些VarDumper中的其他配置方法.
最易于放置这个辅助函数的地方是在 app
下建立的 helpers.php
文件,可以把它添加到 composer.json
来实现自动加载:
"autoload": {
"files": [
"app/helpers.php"
],
},
...
你还可以在这里放置其他的辅助函数,形式可参考Laravel的
/Illuminate/Foundation/helpers.php
文件。如果你仅添加与开发过程相关的函数,这个文件可以配置在autoload-dev
的自动加载项里。此外,如果你希望覆盖Laravel的dd()
函数(或其他任何Laravel辅助函数) 而不是为自定义函数使用其他名称, 你需要在require __DIR__.'/../vendor/autoload.php'
这行之前使用require
指令导入你的辅助函数文件。
我们将在新的 app/helpers.php
文件里创建一个新的 ddd()
函数,它可以接受我们需要dump输出的变量,还有用于自定义输出的其他变量。首先,让我们从一个仅模拟内置 dd()
函数的而不增加其他功能的函数开始。
<?php
use Illuminate\Support\Debug\HtmlDumper;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
function ddd($variable)
{
$cloner = new VarCloner();
$dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper();
$dumper->dump($cloner->cloneVar($variable));
die(1);
}
VarDumper
首先通过Cloner复制输入的变量,然后用Dumper向浏览器或终端输出它。VarCloner
类和它创建的 Data
对象都有一些非常便捷的配置方法可加以利用。在Cloner中, setMaxString()
会按特定长度截断长文本,setMaxItems()
会限制超过一级嵌套的输出项数量。 setMaxItems(6)
会将输出:
array:2 [
0 => array:5 [
"id" => 1
"foo" => "FooValue1"
"bar" => "BarValue1"
"baz" => "BazValue1"
"qux" => array:2 [
"average" => 3.0
"standard_deviation" => 1.0
]
]
0 => array:5 [
"id" => 1
"foo" => "FooValue2"
"bar" => "BarValue2"
"baz" => "BazValue2"
"qux" => array:2 [
"average" => 5.0
"standard_deviation" => 1.0
]
]
...
变成这样:
array:2 [
0 => array:5 [
"id" => 1
"foo" => "FooValue1"
"bar" => "BarValue1"
"baz" => "BazValue1"
"qux" => array:2 [ …2]
]
1 => array:5 [
"id" => 2
…4
]
...
……对于很长的输出,快速浏览前几项是较好的方法。
(请注意,给这些配置方法传递 -1
等同于不限制输出)
VarCloner
输出的结果可以在输出前进一步修改, withMaxItemsPerDepth()
这个方法会限制每一层显示的项目数量,
而 withMaxDepth()
,是一个最有助于调整输出结构的方法,它会限制展开形式下显示的子嵌套层级数。在下面的例子中,使用 withMaxDepth(2)
会折叠所有的 qux
数组, 从而得到:
array:2 [
0 => array:5 [
"id" => 1
"foo" => "FooValue1"
"bar" => "BarValue1"
"baz" => "BazValue1"
"qux" => array:2 [ …2]
]
1 => array:5 [
"id" => 1
"foo" => "FooValue2"
"bar" => "BarValue2"
"baz" => "BazValue2"
"qux" => array:2 [ …2]
]
...
在辅助函数中,我们可以设置一些参数项,让我们可以在调用时控制 ddd()
输出的行为:
function ddd($variable, $depth = -1, $stringLength = 20)
{
$cloner = new VarCloner();
$cloner->setMaxString($stringLength);
$dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper();
$dumper->dump($cloner->cloneVar($variable)->withMaxDepth($depth));
die(1);
}
现在如果我们这样调用 ddd($someVariable, 2)
,输出会被限制在2层嵌套,长字符串会被截断至20个字符。如果这样得不到足够的信息,可以简单的修改参数去增加一层显示 ddd($someVariable, 3)
。这是一个调整调试输出的快捷方法,特别是当你需要查看一些嵌套很深的JSON对象或很多内容的Eloquent模型。
选择之二: Kint
另一个选择是使用调试库 Kint 来完成这个任务, 但是产生的结果会有轻微差异。Kint提供了一些方便的增强功能,可用于控制浏览器中的调试输出,但和VarDumper类似,它给命令行终端提供了两个有用的配置项: $maxLevels
和 $maxStrLength
。
首先,使用 composer 安装 Kint:
composer require raveren/kint
接着,在之前我们创建的 app/helpers.php
文件中,我们可以自定义一个 debug
函数:
function debug($variable, $depth = null)
{
\Kint::$maxLevels = $depth;
return ddd($variable);
}
注意,Kint 内置了
ddd()
和dump()
函数,因此我们需要使用新名称,debug()
函数会调用 Kint 内置的ddd()
函数。
就像这样,我们可以调用 debug($someVariable, 3)
再次缩减输出。像 VarDumper 一样,Kint 的输出格式和颜色都很好,使用 Kint 代替 VarDumper 的一个优点是,Kint 的输出在其结果中包含有关数据类型的更多详细信息,这使得很容易发现某些应该是整数的值实际上是一个 float
。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。