[编程技巧] 命令行友好的 dd () 调试方法

24pqba0DHa.png!large

每个Laravel开发者的调试工具中,都有一个最要而不起眼的 dd() (dump and die)辅助函数,它可以输出变量内容并终止代码运行。在浏览器中, dd() 函数输出的是一个易读的树状结构,还带有可点击的小箭头按钮,用于展开或隐藏子嵌套结构。而在命令行终端,情况就大不相同了。

在进行大量测试时,我们会花费相当多的时间在终端中检查输出,而不是在浏览器。在对PHPUnit中失败的测试进行故障排除时,你通常会需要 dd() 函数输出数组、集合、类、Eloquent模型、API调用返回的JSON。 dd() 在命令行的输出和HTML一样是结构化的,但很多时候输出要么特别长,要么有很深的嵌套,导致你需要经常上下滚动去寻找你需要的信息。如果输出信息的长度超出了终端的缓冲区,那么将很难,甚至无法找到输出的顶部。

幸运的是,自定义 dd() 函数是简单的,我们可以通过定制来调整终端输出的内容,帮助你快速找到感兴趣的信息,而不至于耗尽你的耐心。只需一个帮助函数,你就可从定制前:

长篇累牍

……到定制后:

清晰易读

……或者其他处于两者之间的效果。

有两种方法可以达成上述目标:

幸运的是,构建自己的定制版本的dd()很简单,以帮助驯服您不必要的终端输出——帮助您快速找到您感兴趣的详细信息,而不会耗尽触控板(和您的耐心)。只需一个助手函数,您就可以做到从这样:

so much scrolling

…到这样:

dd tamed

…或介于两者之间的任何东西。

有两种方法可以实现此目的:

选择之一:使用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" => 24
  ]
  ...

……对于很长的输出,快速浏览前几项是较好的方法。
(请注意,给这些配置方法传递 -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 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://tighten.co/blog/a-better-dd-for-...

译文地址:https://learnku.com/laravel/t/41115

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!