|
| 1 | +.. index:: |
| 2 | + single: VarDumper |
| 3 | + single: Components; VarDumper |
| 4 | + |
| 5 | +Advanced Usage of the VarDumper Component |
| 6 | +========================================= |
| 7 | + |
| 8 | +``dump()`` function is just a thin wrapper and a more convenient way to call |
| 9 | +:method:`VarDumper::dump() <Symfony\\Component\\VarDumper\\VarDumper::dump>`. |
| 10 | +You can change the behavior of this function by calling |
| 11 | +:method:`VarDumper::setHandler($callable) <Symfony\\Component\\VarDumper\\VarDumper::setHandler>`: |
| 12 | +calls to ``dump()`` will then be forwarded to ``$callable``. |
| 13 | + |
| 14 | +Cloners |
| 15 | +~~~~~~~ |
| 16 | + |
| 17 | +A cloner is used to create an intermediate representation of any PHP variable. |
| 18 | +Its output is a :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` |
| 19 | +object that wraps this representation. |
| 20 | + |
| 21 | +You can create a :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` |
| 22 | +object this way:: |
| 23 | + |
| 24 | + $cloner = new VarCloner(); |
| 25 | + $data = $cloner->cloneVar($myVar); |
| 26 | + |
| 27 | +A cloner also applies limits when creating this representation, so that the |
| 28 | +corresponding Data object could represent only a subset of the cloned variable. |
| 29 | +Before :method:`Symfony\\Component\\VarDumper\\Cloner\\VarCloner::cloneVar`, |
| 30 | +you can configure these limits: |
| 31 | + |
| 32 | +* :method:`Symfony\\Component\\VarDumper\\Cloner\\VarCloner::setMaxItems` |
| 33 | + configures the maximum number of items that will be cloned *past the first |
| 34 | + nesting level*. Items are counted using a breadth-first algorithm so that |
| 35 | + lower level items have higher priority than deeply nested items; |
| 36 | +* :method:`Symfony\\Component\\VarDumper\\Cloner\\VarCloner::setMaxString` |
| 37 | + configures the maximum number of characters that will be cloned before |
| 38 | + cutting overlong strings; |
| 39 | +* in both cases, specifying `-1` removes any limit. |
| 40 | + |
| 41 | +Before dumping it, you can further limit the resulting |
| 42 | +:class:`Symfony\\Component\\VarDumper\\Cloner\\Data` object by calling its |
| 43 | +:method:`Symfony\\Component\\VarDumper\\Cloner\\Data::getLimitedClone` |
| 44 | +method: |
| 45 | + |
| 46 | +* the first ``$maxDepth`` argument allows limiting dumps in the depth dimension, |
| 47 | +* the second ``$maxItemsPerDepth`` limits the number of items per depth level, |
| 48 | +* and the last ``$useRefHandles`` defaults to ``true`` but allows removing |
| 49 | + internal objects' handles for sparser output, |
| 50 | +* but unlike the previous limits on cloners that remove data on purpose, |
| 51 | + these can be changed back and forth before dumping since they do not affect |
| 52 | + the intermediate representation internally. |
| 53 | + |
| 54 | +.. note:: |
| 55 | + |
| 56 | + When no limit is applied, a :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` |
| 57 | + object is as accurate as the native :phpfunction:`serialize` function |
| 58 | + and thus could have a wider purpose than strictly dumping for debugging. |
| 59 | + |
| 60 | +Dumpers |
| 61 | +~~~~~~~ |
| 62 | + |
| 63 | +A dumper is responsible for outputting a string representation of a PHP variable, |
| 64 | +using a :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` object as input. |
| 65 | +The destination and the formatting of this output vary with dumpers. |
| 66 | + |
| 67 | +This component comes with an :class:`Symfony\\Component\\VarDumper\\Dumper\\HtmlDumper` |
| 68 | +for HTML output and a :class:`Symfony\\Component\\VarDumper\\Dumper\\CliDumper` |
| 69 | +for optionally colored command line output. |
| 70 | + |
| 71 | +For example, if you want to dump some ``$variable``, just do:: |
| 72 | + |
| 73 | + $cloner = new VarCloner(); |
| 74 | + $dumper = new CliDumper(); |
| 75 | + |
| 76 | + $dumper->dump($cloner->cloneVar($variable)); |
| 77 | + |
| 78 | +By using the first argument of the constructor, you can select the output |
| 79 | +stream where the dump will be written. By default, the ``CliDumper`` writes |
| 80 | +on ``php://stdout`` and the ``HtmlDumper`` on ``php://output``, but any PHP |
| 81 | +stream (resource or URL) is acceptable. |
| 82 | + |
| 83 | +Instead of a stream destination, you can also pass it a ``callable`` that |
| 84 | +will be called repeatedly for each line generated by a dumper. This |
| 85 | +callable can be configured using the first argument of a dumper's constructor, |
| 86 | +but also using the |
| 87 | +:method:`Symfony\\Component\\VarDumper\\Dumper\\AbstractDumper::setOutput` |
| 88 | +method or the second argument of the |
| 89 | +:method:`Symfony\\Component\\VarDumper\\Dumper\\AbstractDumper::dump` method. |
| 90 | + |
| 91 | +For example, to get a dump as a string in a variable, you can do:: |
| 92 | + |
| 93 | + $cloner = new VarCloner(); |
| 94 | + $dumper = new CliDumper(); |
| 95 | + $output = ''; |
| 96 | + |
| 97 | + $dumper->dump( |
| 98 | + $cloner->cloneVar($variable), |
| 99 | + function ($line, $depth) use (&$output) { |
| 100 | + // A negative depth means "end of dump" |
| 101 | + if ($depth >= 0) { |
| 102 | + // Adds a two spaces indentation to the line |
| 103 | + $output .= str_repeat(' ', $depth).$line."\n"; |
| 104 | + } |
| 105 | + } |
| 106 | + ); |
| 107 | + |
| 108 | + // $output is now populated with the dump representation of $variable |
| 109 | + |
| 110 | +An other option for doing the same could be:: |
| 111 | + |
| 112 | + cloner = new VarCloner(); |
| 113 | + $dumper = new CliDumper(); |
| 114 | + $output = fopen('php://memory', 'r+b'); |
| 115 | + |
| 116 | + $dumper->dump($cloner->cloneVar($variable), $output); |
| 117 | + rewind($output); |
| 118 | + $output = stream_get_contents($output); |
| 119 | + |
| 120 | + // $output is now populated with the dump representation of $variable |
| 121 | + |
| 122 | +Dumpers implement the :class:`Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface` |
| 123 | +interface that specifies the |
| 124 | +:method:`dump(Data $data) <Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface::dump>` |
| 125 | +method. They also typically implement the |
| 126 | +:class:`Symfony\\Component\\VarDumper\\Cloner\\DumperInterface` that frees |
| 127 | +them from re-implementing the logic required to walk through a |
| 128 | +:class:`Symfony\\Component\\VarDumper\\Cloner\\Data` object's internal structure. |
| 129 | + |
| 130 | +Casters |
| 131 | +~~~~~~~ |
| 132 | + |
| 133 | +Objects and resources nested in a PHP variable are casted to arrays in the |
| 134 | +intermediate :class:`Symfony\\Component\\VarDumper\\Cloner\\Data` |
| 135 | +representation. You can tweak the array representation for each object/resource |
| 136 | +by hooking a Caster into this process. The component already includes many |
| 137 | +casters for base PHP classes and other common classes. |
| 138 | + |
| 139 | +If you want to build your own Caster, you can register one before cloning |
| 140 | +a PHP variable. Casters are registered using either a Cloner's constructor |
| 141 | +or its ``addCasters()`` method:: |
| 142 | + |
| 143 | + $myCasters = array(...); |
| 144 | + $cloner = new VarCloner($myCasters); |
| 145 | + |
| 146 | + // or |
| 147 | + |
| 148 | + $cloner->addCasters($myCasters); |
| 149 | + |
| 150 | +The provided ``$myCasters`` argument is an array that maps a class, |
| 151 | +an interface or a resource type to a callable:: |
| 152 | + |
| 153 | + $myCasters = array( |
| 154 | + 'FooClass' => $myFooClassCallableCaster, |
| 155 | + ':bar resource' => $myBarResourceCallableCaster, |
| 156 | + ); |
| 157 | + |
| 158 | +As you can notice, resource types are prefixed by a ``:`` to prevent |
| 159 | +colliding with a class name. |
| 160 | + |
| 161 | +Because an object has one main class and potentially many parent classes |
| 162 | +or interfaces, many casters can be applied to one object. In this case, |
| 163 | +casters are called one after the other, starting from casters bound to the |
| 164 | +interfaces, the parents classes and then the main class. Several casters |
| 165 | +can also be registered for the same resource type/class/interface. |
| 166 | +They are called in registration order. |
| 167 | + |
| 168 | +Casters are responsible for returning the properties of the object or resource |
| 169 | +being cloned in an array. They are callables that accept four arguments: |
| 170 | + |
| 171 | +* the object or resource being casted, |
| 172 | +* an array modelled for objects after PHP's native ``(array)`` cast operator, |
| 173 | +* a :class:`Symfony\\Component\\VarDumper\\Cloner\\Stub` object |
| 174 | + representing the main properties of the object (class, type, etc.), |
| 175 | +* true/false when the caster is called nested is a structure or not. |
| 176 | + |
| 177 | +Here is a simple caster not doing anything:: |
| 178 | + |
| 179 | + function myCaster($object, $array, $stub, $isNested) |
| 180 | + { |
| 181 | + // ... populate/alter $array to your needs |
| 182 | + |
| 183 | + return $array; |
| 184 | + } |
| 185 | + |
| 186 | +For objects, the ``$array`` parameter comes pre-populated using PHP's native |
| 187 | +``(array)`` casting operator or with the return value of ``$object->__debugInfo()`` |
| 188 | +if the magic method exists. Then, the return value of one Caster is given |
| 189 | +as argument to the next Caster in the chain. |
| 190 | + |
| 191 | +When casting with the ``(array)`` operator, PHP prefixes protected properties |
| 192 | +with a ``\0*\0`` and private ones with the class owning the property: |
| 193 | +e.g. ``\0Foobar\0`` prefixes all private properties of objects of type Foobar. |
| 194 | +Casters follow this convention and add two more prefixes: ``\0~\0`` is used |
| 195 | +for virtual properties and ``\0+\0`` for dynamic ones (runtime added |
| 196 | +properties not in the class declaration). |
| 197 | + |
| 198 | +.. note:: |
| 199 | + |
| 200 | + Although you can, it is best advised not to alter the state of an object |
| 201 | + while casting it in a Caster. |
| 202 | + |
| 203 | +.. tip:: |
| 204 | + |
| 205 | + Before writting your own casters, you should check the existing ones. |
0 commit comments