VarDumper组件的高级用法

3.4 版本
维护中的版本

dump()函数只是一个轻量化的打包儿器,以及一个调用VarDumper::dump()的更方便的方式。你可以通过VarDumper::setHandler($callable)来改变此函数的行为。调用dump()之后就会被转发给callable

通过添加一个handler,你可以自定义ClonersDumpers以及Casters,就像下面解释的那样。一个handler函数的简单实现,可能看起来像下面这样:

1
2
3
4
5
6
7
8
9
10
11
use Symfony\Component\VarDumper\VarDumper;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
 
VarDumper::setHandler(function ($var) {
    $cloner = new VarCloner();
    $dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper();
 
    $dumper->dump($cloner->cloneVar($var));
});

Cloners 

Cloner用于创建任意PHP变量的中间层(intermediate representation)。它输出一个Data对象,以便打包这个层。

你可以按下述方式创建Data对象:

1
2
3
4
5
6
7
8
use Symfony\Component\VarDumper\Cloner\VarCloner;
 
$cloner = new VarCloner();
$data = $cloner->cloneVar($myVar);
// this is commonly then passed to the dumper
// see the example at the top of this page
// 这(数据)通常要传到dumper中,参考前例
// $dumper->dump($data);

cloner还能在创建表现层时施加限制,以便相应的数据对象能够仅以被克隆变量的子集来呈现。在调用clonerVar()之前,你应该配置这些限制:

setMaxItems()

配置即将经过第一个嵌套级别(past the first nesting level)被克隆的元素的最大值。元素被统计时使用的是宽度优先(breadth-first)的算法,以便低级别的元素相对于深层嵌套的元素有更高的优先级(priority)。

setMaxString()

在裁切超长字符串之前,配置将被克隆的字符最大值。

两种情况下,指定-1即代表去除任何限制。

在剥离变量之前,通过下列方法,你可以进一步限制即将成为结果的Data对象:

withMaxDepth()

在深度上的剥离限制。

withMaxItemsPerDepth()

在每一层深度上所允许的最大元素数量。

withRefHandles()

允许移除内部对象对零星输出的处理(对测试有用)。

不像cloner在之前的“以移除数据为目的”的限制,这几个方法可以在剥离之前修改来修改去,因为它们并不对内部的中间层有所影响。

当没有任何限制时,Data与原生的serialize可以划等号,可以用于除错时的(变量)剥离之目的。

Dumpers 

dumper负责生成PHP变量的字符串表现层,使用一个Data对象作为输入。输出的目标和格式则因dumpers而异。

组件内置了一个用于HTML输出的HtmlDumper,以及一个用于“可选加亮”的命令行输出的CliDumper

例如,若你要剥离一些$variable变量,只需:

1
2
3
4
5
6
7
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
 
$cloner = new VarCloner();
$dumper = new CliDumper();
 
$dumper->dump($cloner->cloneVar($variable));

使用构造构造器的第一个参数,,你可以选择dump将被写入的输出流(output stream)。默认时,CliDumper写入php://stdout,而HtmlDumper写入php://output。然而任意PHP stream(resource或URL)都是可接受的。

若不使用流目标(stram desination),你也可传入一个callable,它将被一个dumper所生成的每一行所重复调用。这个callable(回调)可以通过dumper的构造器的第一个参数来配置,但也可以使用setOutput()方法,或者是dump()方法的第二个参数(来配置)。

例如,为了把一个变量剥离成一个字符串,你可以:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
 
$cloner = new VarCloner();
$dumper = new CliDumper();
$output = '';
 
$dumper->dump(
    $cloner->cloneVar($variable),
    function ($line, $depth) use (&$output) {
        // A negative depth means "end of dump"
        if ($depth >= 0) {
            // Adds a two spaces indentation to the line
            $output .= str_repeat('  ', $depth).$line."\n";
        }
    }
);
 
// $output is now populated with the dump representation of $variable
// $output现在被装入变量$variable的剥离内容

做同样事的另一个选择:

1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
 
$cloner = new VarCloner();
$dumper = new CliDumper();
$output = fopen('php://memory', 'r+b');
 
$dumper->dump($cloner->cloneVar($variable), $output);
$output = stream_get_contents($output, -1, 0);
 
// $output is now populated with the dump representation of $variable
// $output现在被装入变量$variable的剥离内容

Dumpers实现的是DataDumperInterface接口,具体化了dump(Data $data)方法。它们也可以去实现DumperInterface接口,该接口把它们(dumpers)从遍历一个Data对象内部结构所需的逻辑中释放出来。

Casters 

嵌套在PHP变量中的对象和资源(objects and resources)是被“cast(投掷)”到Data中间层的数组中。通过把“投掷器(caster)”打到进程中,你可以对每一个对象/资源来修改这个数组呈现。本组件内置了很多casters,用于基础PHP类和其他常规类。

如果你需要构建自己的Caster,你要在克隆PHP变量之前注册它。Casters可以使用Cloner的构造器,或是其addCasters()方法:

1
2
3
4
5
6
7
8
use Symfony\Component\VarDumper\Cloner\VarCloner;
 
$myCasters = array(...);
$cloner = new VarCloner($myCasters);
 
// or 或
 
$cloner->addCasters($myCasters);

提供的$myCasters参数是一个数组,映射的是一个类、一个接口或一个资源类型(resource type)的回调(callable):

1
2
3
4
$myCasters = array(
    'FooClass' => $myFooClassCallableCaster,
    ':bar resource' => $myBarResourceCallableCaster,
);

如你所见,资源类型使用了一个:前缀,为的是防止类名冲突。

因为一个对象有一个主class,和潜在的许多父类或接口,很多casters可以被应用到一个对象。这时,casters被一个接一个地调用,从绑定了接口、父类然后是主类(main class)的casters开始。几个casters可以被注册到同一资源/类/接口。它们按照注册顺序来调用。

casters负责返回数组方式的被克隆的对象属性或资源。它们是接收四个参数的回调(callables):

  • 被投掷的对象或资源;

  • 跟在PHP原生cast操作符(array)后面的一个基于对象建模的数组;

  • 一个用于呈现对象(类、types等)的主属性(main properties)Stub对象;

  • true/false。caster被调用时是否是嵌套结构?

这里有个简单的caster,它没有做任何事:

1
2
3
4
5
6
function myCaster($object, $array, $stub, $isNested)
{
    // ... populate/alter $array to your needs
    // ... 根据你的需求来载入/改变 $array
    return $array;
}

对于对象来说,$array参数自带了:预加载(pre-populated)时使用的PHP原生(array) casting操作符,或是当魔术方法存在时$object->__debugInfo()的返回值。然后,一个Caster的返回值被当做数组参数,给到链路(chain)中的另一个Caster。

当使用(array)操作符进行casting时,PHP对受保护属性添加了前缀\0*\0,对private属性则是类所拥有的属性。例如,\0Foobar\0前缀将添加到type Foobar这个对象的所有私有属性。Casters遵循这个约定,并添加了两个前缀:\0~\0用于虚拟属性(virtual properties),而\0+\0用于动态属性(runtime运行时添加的属性,而非类声明里的)

虽然可以,但还是建议你不要在将对象投掷到Caster时,改变该对象的状态。

自己写casters之前,应当参考现有的caster程序。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)