VarDumper and DebugBundle #10640

Merged
merged 31 commits into from Sep 23, 2014
@nicolas-grekas
Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets none
License MIT
Doc PR symfony/symfony-docs#4243

From a user land point of view, this PR creates a global dump() function that is to be used instead of var_dump(). The component can be used standalone in any dev workflow. Please see the provided README for details.

When used with the Framework bundle, variables passed to dump() are dumped in a new dedicated panel in the web toolbar. The function is also available in twig templates.

Regarding the implementation, I'm pretty sure you'll find a lot to comment. As I'm sure of nothing else, not even the names of things, please do.

I tried to organize this PR in several commits, from the most fundamental algorithm to pure Symfony glue.
I suggest you follow this order while progressing in the review and the discussion around this PR, so that we can together validate commits one after the other.

Don't hesitate to fork the PR and submit PR on it, I'll cherry-pick your patches.

TODO:

  • open a doc PR: symfony/symfony-docs#4243
  • open a PR on the Standard edition: symfony/symfony-standard#710
  • prefix the CSS classes
  • tests for the DebugBundle + other Symfony glue classes
  • inline css and js for compat with e.g. Silex
  • finish and merge nicolas-grekas/Patchwork-Dumper#5 for better UX
  • show a dump excerpt on hovering the icon in the toolbar
  • verify README and comments
  • validate interfaces/names (Caster / Cloner / Dumper)
  • validate new VarDumper component + DebugBundle
  • validate Resource/ext/ vs independent repos.
  • test and define behavior after KernelEvents::RESPONSE
  • update dependencies between components/bundles and composer.json files
  • no hard dep on iconv

Not for this PR but might be worth later:

  • show a light stack trace + timing + memory at debug() calls
  • create a "theme" concept for custom colors/UX
@Koc
Koc commented Apr 5, 2014

Awesome bulk of work was done! Very interesting component. I hope it will be part of Symfony.

@romainneutron romainneutron commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/Caster/SplCaster.php
+
+ return $a;
+ }
+
+ public static function castSplFixedArray(\SplFixedArray $c, array $a)
+ {
+ $a = array_merge($a, $c->toArray());
+
+ return $a;
+ }
+
+ public static function castSplObjectStorage(\SplObjectStorage $c, array $a)
+ {
+ foreach ($c as $k => $obj) {
+ $a[$k] = $obj;
+ if (null !== $i = $c->getInfo()) $a["\0~\0$k"] = $i;
@romainneutron
Symfony member

code style : it should be on two lines, using brackets

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pborreli pborreli commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/Resources/ext/README.rst
+=======================
+
+This extension adds a ``symfony_zval_info($key, $array, $options = 0)`` function that:
+
+- exposes zval_hash/refcounts, allowing e.g. efficient exploration of arbitrary structures in PHP,
+- does work with references, preventing memory copying.
+
+Its behavior is about the same as:
+
+.. code-block:: php
+
+ <?php
+
+ function symfony_zval_info($key, $array, $options = 0)
+ {
+ // $options is currenlty not used, but could be in future version.
@pborreli
pborreli added a note Apr 5, 2014

currenlty -> currently

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pborreli pborreli commented on an outdated diff Apr 5, 2014
...le/WebProfilerBundle/Resources/public/js/var_debug.js
+
+ function htmlizeData(data, tags, title)
+ {
+ var i, e, t, b;
+
+ ++counter;
+ title = title || [];
+ tags = tags || '';
+
+ if (refs[counter]) push('#' + counter, 'ref target');
+ else if (iRefs[counter]) push('r' + iRefs[counter], 'ref handle');
+ else if (iRefs[-counter]) push('R' + iRefs[-counter], 'ref alias');
+
+ switch (true)
+ {
+ case null === data: data = 'null';
@pborreli
pborreli added a note Apr 5, 2014

[cs] case(s) should be indented

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 2 others commented on an outdated diff Apr 5, 2014
src/Symfony/Bridge/Twig/Extension/VarDebugExtension.php
+ if (2 === $count) {
+ $vars = array();
+ foreach ($context as $key => $value) {
+ if (! $value instanceof \Twig_Template) {
+ $vars[$key] = $value;
+ }
+ }
+ } elseif (3 === $count) {
+ $vars = func_get_arg(2);
+ } else{
+ $vars = array_slice(func_get_args(), 2);
+ }
+
+ debug($vars);
+
+ return '';
@stof
Symfony member
stof added a note Apr 5, 2014

This looks weird to me. The meaning of a Twig function is that it returns some content. If debug() is outputing the debugging data, there is 2 solutions to respect the Twig semantic:

  • make it a Twig tag rather than a Twig function
  • use output buffering to return the output

This is the indented behavior: rather than outputting anything, the debug() function fills in a data collector. The data is then displayed in the toolbar. The same occurs when debug() is used in PHP code.

@Koc
Koc added a note Apr 6, 2014

So construction like debug($variable); exit; will not output anything?

It depends on how you configure the debug handler. In CLI mode, vars are displayed on stderr. In web mode, data is collected for displaying in the toolbar. So I think that yes: debug+die is not expected workflow currently.

@stof
Symfony member
stof added a note Apr 6, 2014

@nicolas-grekas then it should not be a Twig function but a tag, to respect the Twig semantic.

It is perfectly fine to collect the output separately, but it should be done in the Twig way

@Koc
Koc added a note Apr 6, 2014

What about two sollutions: override standard Twig's dump function http://twig.sensiolabs.org/doc/functions/dump.html for immediately output as now and tag for collect?

@Koc
Koc added a note Apr 6, 2014

Maybe same for native functions: debug and debug_collect.

@stof
Symfony member
stof added a note Apr 6, 2014

@Koc The VarDebug component is not about immediate output. So overwriting the standard dump function would be weird IMO.

and a debug_collect function would still suffer from the same issue. Collecting the debug of the variable is not a function is the Twig semantic, it is a tag. This ends here.

@Koc
Koc added a note Apr 6, 2014

You misunderstood me: I'm proposing debug_collect function for the native php (for using in controllers).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...FrameworkBundle/DependencyInjection/Configuration.php
@@ -497,4 +498,26 @@ private function addSerializerSection(ArrayNodeDefinition $rootNode)
->end()
;
}
+
+ private function addVarDebugSection(ArrayNodeDefinition $rootNode)
+ {
+ $rootNode
+ ->children()
+ ->arrayNode('var_debug')
+ ->info('va_debug configuration')
@stof
Symfony member
stof added a note Apr 5, 2014

typo: var_debug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...FrameworkBundle/DependencyInjection/Configuration.php
@@ -497,4 +498,26 @@ private function addSerializerSection(ArrayNodeDefinition $rootNode)
->end()
;
}
+
+ private function addVarDebugSection(ArrayNodeDefinition $rootNode)
+ {
+ $rootNode
+ ->children()
+ ->arrayNode('var_debug')
+ ->info('va_debug configuration')
+ ->children()
+ ->integerNode('max_items')
+ ->info('Max number of displayed items, all levels included, 0 means no limit, -1 only first level')
+ ->min(0)
@stof
Symfony member
stof added a note Apr 5, 2014

the info explains that -1 means only first level, but this is preventing to pass -1. There is a mistake somewhere

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...FrameworkBundle/DependencyInjection/Configuration.php
@@ -497,4 +498,26 @@ private function addSerializerSection(ArrayNodeDefinition $rootNode)
->end()
;
}
+
+ private function addVarDebugSection(ArrayNodeDefinition $rootNode)
+ {
+ $rootNode
+ ->children()
+ ->arrayNode('var_debug')
+ ->info('va_debug configuration')
+ ->children()
+ ->integerNode('max_items')
+ ->info('Max number of displayed items, all levels included, 0 means no limit, -1 only first level')
+ ->min(0)
+ ->defaultValue(500)
+ ->end()
+ ->integerNode('max_string')
@stof
Symfony member
stof added a note Apr 5, 2014

shouldn't it be max_string_length instead ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...workBundle/DependencyInjection/FrameworkExtension.php
@@ -130,6 +130,21 @@ public function load(array $configs, ContainerBuilder $container)
$loader->load('serializer.xml');
}
+ $loader->load('var_debug.xml');
+
+ if (!$container->getParameter('var_debug.collector.class')) {
@stof
Symfony member
stof added a note Apr 5, 2014

this check should be removed, as the parameter is not set yet in the temp container passed to the extension and so the condition will always be true (and if you set the parameter yourself in the main config, it will win over the parameter set in the DI extension anyway)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...workBundle/DependencyInjection/FrameworkExtension.php
@@ -130,6 +130,21 @@ public function load(array $configs, ContainerBuilder $container)
$loader->load('serializer.xml');
}
+ $loader->load('var_debug.xml');
+
+ if (!$container->getParameter('var_debug.collector.class')) {
+ $container->setParameter(
+ 'var_debug.collector.class',
+ 'Symfony\Component\VarDebug\Collector\\'.(extension_loaded('symfony_debug') ? 'Ext' : 'Php').'Collector'
+ );
+ }
+
+ if (isset($config['var_debug'])) {
@stof
Symfony member
stof added a note Apr 5, 2014

you should add a call to addDefaultsIfNotSet() in the configuration class, so that the default values of the configuration tree are used even when you don't put var_debug: ~ in your config

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -54,6 +54,13 @@ public function boot()
if ($trustedHosts = $this->container->getParameter('kernel.trusted_hosts')) {
Request::setTrustedHosts($trustedHosts);
}
+
+ $container = $this->container;
+
+ set_debug_handler(function ($var) use ($container) {
+ $data = $container->get('var_debug.collector')->collect($var);
+ $container->get('var_debug.dumper.cli')->dump($data);
@stof
Symfony member
stof added a note Apr 5, 2014

shouldn't the CLI dumper be used only in a CLI context ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...Bundle/FrameworkBundle/Resources/config/var_debug.xml
+<?xml version="1.0" ?>
+
+<container xmlns="http://symfony.com/schema/dic/services"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
+
+ <parameters>
+ <parameter key="var_debug.collector.class"><!-- empty for auto-selection --></parameter>
+ <parameter key="var_debug.dumper.json.class">Symfony\Component\VarDebug\Dumper\JsonDumper</parameter>
+ <parameter key="var_debug.dumper.html.class">Symfony\Component\VarDebug\Dumper\HtmlDumper</parameter>
+ <parameter key="var_debug.dumper.cli.class">Symfony\Component\VarDebug\Dumper\CliDumper</parameter>
+ </parameters>
+
+ <services>
+ <service id="var_debug.collector" class="%var_debug.collector.class%">
+ </service>
@stof
Symfony member
stof added a note Apr 5, 2014

you should use a self-closing tag for consistency with the Symfony code base

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...Bundle/FrameworkBundle/Resources/config/var_debug.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+
+<container xmlns="http://symfony.com/schema/dic/services"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
+
+ <parameters>
+ <parameter key="var_debug.collector.class"><!-- empty for auto-selection --></parameter>
@stof
Symfony member
stof added a note Apr 5, 2014

just don't set it there, and set it always in the DI extension

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...le/WebProfilerBundle/Resources/public/js/var_debug.js
@@ -0,0 +1,243 @@
+"use strict";
@stof
Symfony member
stof added a note Apr 5, 2014

Please don't put a use strict outside functions, as this will make all JS code running in strict mode (it puts the global scope in strict mode), which can break other JS on the page. It is not sage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...le/WebProfilerBundle/Resources/public/js/var_debug.js
+ var i, e, t, b;
+
+ ++counter;
+ title = title || [];
+ tags = tags || '';
+
+ if (refs[counter]) push('#' + counter, 'ref target');
+ else if (iRefs[counter]) push('r' + iRefs[counter], 'ref handle');
+ else if (iRefs[-counter]) push('R' + iRefs[-counter], 'ref alias');
+
+ switch (true)
+ {
+ case null === data: data = 'null';
+ case true === data:
+ case false === data:
+ default:
@stof
Symfony member
stof added a note Apr 5, 2014

should't default be the last case ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...rBundle/Resources/views/Collector/var_debug.html.twig
@@ -0,0 +1,65 @@
+{% extends 'WebProfilerBundle:Profiler:layout.html.twig' %}
+
+{% block toolbar %}
+
+ {% set dumps_count = collector.dumps|length %}
+
+ {% set icon %}
+ <img alt="debug()" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAt1BMVEUAAAANDQ0AAAAhISESEhIAAABEREQAAAAAAAAQEBAAAAAAAAAFBQUMDAwVFRU2NjYJCQkGBgYNDQ0AAAA+Pj5FRUUuLi4QEBAuLi41NTUICAgFBQUAAAAAAAA6Ojo+Pj4jIyMJCQkEBAQAAAATExMqKipAQEAbGxssLCwAAAA6OjoKCgodHR0fHx89PT0ZGRlKSkpOTk5PT09dXV1SUlJaWlpYWFhGRkZVVVVERERiYmJUVFRISEj7yUYlAAAAOHRSTlMAahiweAX4AgFvCAo4Y4TjUyxmKO773HLO3EQ2JBHv/bRYOw59xPWW0B/5T56o5o7//////////vCDrPIAAAGKSURBVCjPbVPneoMwDBQrQPYgjCxSMpu2qQcz8fs/V22RfDSl+oGFzrKl0xl+mQP7zAUb/jPb2X3eTjunjWJCz7h9dQH+wo4DoE8GEY8GEx1/X9ImrlFxfue8Y7gTjDTYW5Txe3jNrmHJs2jcoHLVCk6NqT7ke326ZbwaPFFH5hWZN90BmNwFWGteNh+rOCbORrn3AdBFUJY79vJoBXadqOU0kJtsBOUCJs0HElFN6dv80JVBC0zJkCXRXpgb6/rWlaAaKEMQzaXFu2KlvxiWXmJbliXvzAPoSs9OvHK4WMKIEpqyeUcZOZgHgp5gKSXiAVKiLA3NMEWPIojHpsfpst/vJ7NT+T1LpLfUjqk8FgsqxLOg8lFQQCpVELbCVCsgW0ld+VWtMGwFSWAikLseoCJBMCShpo9tavrSAOnbMB/pq4mP6UZTxDMkfkNjJP45sphWamRMjayiMY6sGbZPqDiPyOgsKPFx2K8yuRAiCLnUMmkLzCd+I7CWNEkjzbaoRVvUzXOoXp7DD5aJLSEAGSFlAAAAAElFTkSuQmCC" />
+ <span class="sf-toolbar-status{% if dumps_count > 0 %} sf-toolbar-status-yellow{% endif %}">{{ dumps_count }}</span>
@stof
Symfony member
stof added a note Apr 5, 2014

I suggest hiding the toolbar element entirely if there is no dumped data (just like the Swiftmailer and form items are hidden), to limit the amount of useless elements in the toolbar (the toolbar becomes broken when the content cannot fit in a single row anymore)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...ymfony/Bundle/WebProfilerBundle/WebProfilerBundle.php
@@ -20,4 +20,13 @@
*/
class WebProfilerBundle extends Bundle
{
+ public function boot()
+ {
+ $container = $this->container;
+
+ set_debug_handler(function ($var) use ($container) {
+ $data = $container->get('var_debug.collector')->collect($var);
+ $container->get('data_collector.var_debug')->dump($data);
@stof
Symfony member
stof added a note Apr 5, 2014

shoudln't this be handled by the FrameworkBundle ? WebProfilerBundle is not responsible for configuring the profiler and its collectors. This is done in FrameworkBundle. WebProfilerBundle is only the web interface to display the profiler data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/Caster/DoctrineCaster.php
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarDebug\Caster;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class DoctrineCaster
+{
+ public static function castCommonProxy(\Doctrine\Common\Proxy\Proxy $p, array $a)
@stof
Symfony member
stof added a note Apr 5, 2014

please add a use statement

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/Caster/PdoCaster.php
@@ -0,0 +1,114 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarDebug\Caster;
+
+use PDO;
+use PDOStatement;
@stof
Symfony member
stof added a note Apr 5, 2014

The Symfony codebase does not put use statements for the global namespace

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...ny/Component/VarDebug/Collector/AbstractCollector.php
+ {
+ $this->prevErrorHandler = set_error_handler(array($this, 'handleError'));
+ try {
+ $data = $this->doCollect($var);
+ } catch (\Exception $e) {
+ restore_error_handler();
+
+ throw $e;
+ }
+ restore_error_handler();
+ $this->prevErrorHandler = null;
+
+ return new Data($data);
+ }
+
+ abstract protected function doCollect($var);
@stof
Symfony member
stof added a note Apr 5, 2014

Please add the phpdoc on the different methods (use {@inheritDoc} for methods documented in the interface)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...ny/Component/VarDebug/Collector/AbstractCollector.php
+ $a = array();
+
+ if (!empty($this->casters['r:'.$type])) {
+ foreach ($this->casters['r:'.$type] as $c) {
+ $a = $this->callCaster($c, $res, $a);
+ }
+ }
+
+ return $a;
+ }
+
+ private function callCaster($callback, $obj, $a)
+ {
+ try {
+ // Ignore invalid $callback
+ $callback = @call_user_func($callback, $obj, $a);
@stof
Symfony member
stof added a note Apr 5, 2014

the naming seems weird. $callback is not the callback anymore after this call. It is the casted data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/Collector/Data.php
+ }
+
+ public function getRawData()
+ {
+ return $this->data;
+ }
+
+ public function dump(DumperInterface $dumper)
+ {
+ $refs = array(0);
+ $dumper->dumpStart();
+ $this->dumpItem($dumper, new Cursor, $refs, $this->data[0][0]);
+ $dumper->dumpEnd();
+ }
+
+ protected function dumpItem($dumper, $cursor, &$refs, $item)
@stof
Symfony member
stof added a note Apr 5, 2014

should be private (we make everything private in Symfony unless we want to provide an extension point, which does not seem to be the case here)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/README.md
@@ -0,0 +1,22 @@
+Symfony debug tools for PHP variables
+=====================================
+
+This package provides a better `debug()` function, that you can use instead of
+`var_dump()`, *better* being for:
+
+- per object and resource types specialized view: e.g. filter out Doctrine noise
+ while dumping a single proxy entity, or get more insight on opened files with
+ `stream_get_meta_data()`. Add your own dedicated `Dumper\Caster` and get the
+ view *you* need.
+- configurable output format: HTML, command line with colors or [a dedicated high
+ accuracy JSON format](Resource/doc/json-spec.md).
@stof
Symfony member
stof added a note Apr 5, 2014

having a doc folder in the component looks weird to me. This should go in the symfony-docs repo itself

This is not an end user doc but a specification that explains why the JsonDumper behaves the way it is

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/Resources/ext/config.m4
@@ -0,0 +1,63 @@
+dnl $Id$
+dnl config.m4 for extension symfony_debug
+
+dnl Comments in this file start with the string 'dnl'.
+dnl Remove where necessary. This file will not work
+dnl without editing.
@stof
Symfony member
stof added a note Apr 5, 2014

Shoudln't this file be cleaned from comments coming from the default template to adapt the file to the extension itself ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/Resources/ext/config.w32
@@ -0,0 +1,13 @@
+// $Id$
+// vim:ft=javascript
@stof
Symfony member
stof added a note Apr 5, 2014

vim setting should be removed IMO (and $Id$ as well)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...fony/Component/VarDebug/Resources/functions/debug.php
+ if (class_exists('Symfony\Component\VarDebug\Dumper\CliDumper')) {
+ $collector = extension_loaded('symfony_debug') ? new ExtCollector : new PhpCollector;
+ $dumper = new CliDumper;
+ $h['handler'] = function ($var) use ($collector, $dumper) {
+ $dumper->dump($collector->collect($var));
+ };
+ } else {
+ $h['handler'] = function ($var) {var_dump($var);};
+ }
+ set_debug_handler($h['handler']);
+ }
+
+ return $h['handler']($var);
+ }
+
+ function set_debug_handler(\Closure $closure)
@stof
Symfony member
stof added a note Apr 5, 2014

couldn't it accept any callable rather than just closures ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 5, 2014
...fony/Component/VarDebug/Resources/functions/debug.php
+
+ if (!isset($reflector)) {
+ $reflector = new ReflectionFunction('set_debug_handler');
+ }
+
+ $h = $reflector->getStaticVariables();
+
+ if (!isset($h['handler'])) {
+ if (class_exists('Symfony\Component\VarDebug\Dumper\CliDumper')) {
+ $collector = extension_loaded('symfony_debug') ? new ExtCollector : new PhpCollector;
+ $dumper = new CliDumper;
+ $h['handler'] = function ($var) use ($collector, $dumper) {
+ $dumper->dump($collector->collect($var));
+ };
+ } else {
+ $h['handler'] = function ($var) {var_dump($var);};
@stof
Symfony member
stof added a note Apr 5, 2014

once any callable is supported, this could become $h['handler'] = 'var_dump'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/composer.json
+ "homepage": "http://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "autoload": {
+ "files": [ "Resources/functions/debug.php" ],
+ "psr-0": { "Symfony\\Component\\VarDebug\\": "" }
+ },
+ "target-dir": "Symfony/Component/ClassLoader"
@stof
Symfony member
stof added a note Apr 5, 2014

I suggest using PSR-4 instead of PSR-0 + target-dir (target-dir is deprecated in composer as it was only a workaround because of the missing PSR-4 spec)

PSR-4 is not used currently in the code base. I'd prefer not being the first to make the move, but move together with all the other components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff Apr 5, 2014
src/Symfony/Component/VarDebug/composer.json
+{
+ "name": "symfony/var-debug",
+ "type": "library",
+ "description": "Symfony debug tools for PHP variables",
+ "keywords": ["dump", "debug"],
+ "homepage": "http://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.3"
+ },
@stof
Symfony member
stof added a note Apr 5, 2014

I would add a suggestion on ext-symfony_debug to make people aware of the available extension

Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof
Symfony member

The root composer.json file needs to be updated:

  • adding the replace clause for the new component
  • handling the loading of the debug() function when using the fullstack repo.

The FrameworkBundle composer.json also needs to be updated to requrie the var-debug component (it is a mandatory dependency).

and the Travis config needs to be updated to run the tests of the C extension as well. It would be easier to run them in the CI if it was a separate repo for the C extension than the PHP code, which would also benefit the installation btw (installing the extension is not done by Composer, and even if it was done in the future, it would not take it from the middle of another package but from PECL). Thus, having the extension in a separate repo will make it easier to handle its versionning (we will be able to have a 1.0 tag for its 1.0 version, which is not the case currently) and will allow to submit it to PECL with its own versionning (having it on PECL mean that Windows users will be able to download the compiled build directly thanks to the PECL infrastructure).
What do you think about split the C extension outside the VarDebug component ? Keeping it in the symfony organization but as a separate repo also mean that the extension can be officially maintained by you (contributors to a C extension are not the same than PHP developers)

@Koc
Koc commented Apr 6, 2014

Should this component respect accepted recently __debugInfo RFC https://wiki.php.net/rfc/debug-info ?

@damienalexandre

Cool stuffs :neckbeard:

Maybe the DoctrineCaster could be improved to be more like the native Doctrine dump function?

They have a great export function doing some transformations on entities Proxy.

@realityking

Great concept but two concerns:

  1. debug() might be a rather common name for a non-namespaced function which might cause conflicts with other libraries.

  2. The PHP implementation would be significantly easier with a class with static methods, simply because there would be no need to use Reflection.

@realityking realityking and 2 others commented on an outdated diff Apr 6, 2014
...fony/Component/VarDebug/Resources/ext/symfony_debug.c
+ case IS_RESOURCE:
+ return "resource";
+
+ default:
+ return "unknown type";
+ }
+}
+
+zend_module_entry symfony_debug_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "symfony_debug",
+ symfony_debug_functions,
+ PHP_MINIT(symfony_debug),
+ PHP_MSHUTDOWN(symfony_debug),
+ PHP_RINIT(symfony_debug),
+ PHP_RSHUTDOWN(symfony_debug),

Not a big deal as this will probably rarely be enabled on production systems but these four entries (PHP_MINIT, PHP_MSHUTDOWN, PHP_RINIT, PHP_RSHUTDOWN) should be replaced with null as those functions contain no code. This nets a small performance improvement and is considered a best practice.

@romainneutron
Symfony member

ping @jpauli

@jpauli
jpauli added a note Apr 8, 2014

This will be a matter of micro or nano seconds, considering compiler optimizations http://lxr.php.net/xref/PHP_5_5/Zend/zend_API.c#1757

And this extension will never happen to be on production servers :-p

I left those functions so that when I'll need them (in the future, probably), I won't have to rewrite them. They come from the skeleton generator as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof
Symfony member

the fatal error in the testsuite is because the autoloading of the var_debug functions is missing in the root composer.json

@nicolas-grekas

Some commits added, see above.

If you want to try now, please use: https://github.com/nicolas-grekas/Patchwork-Dumper

I'll keep it in sync with this PR so you can enjoy debug() right now.

@nicolas-grekas

Pour les lecteurs français, consultez également la présentation faite hier au Symfony Live Paris :
https://speakerdeck.com/nicolasgrekas/debug-plus-symfony

@romainneutron
Symfony member

After thinking a bit more about the debug function, rather than a debug function, the behaviour looks like a snapshoter, a screenshoter, a polaroid camera.
We discussed with Nicolas about taking lots of "snapshots" of an object during the lifecycle of a program would naturally lead to data visualisation and diffs.
One of the powerful features of this component is to understand and visualize very quickly what's going on in the code.

@Taluu

Even if this looks promising, I'm not sure that this should be in a new component rather than plain old Debug component (as it is a tool to debug things)...

@stof stof added the Feature label Apr 9, 2014
@nicolas-grekas

Update:

  • @Koc commit nicolas-grekas@92b1502 is for you,
  • I also did a first round of fixes for composer/components/bundles dependencies,
  • Many thanks to @ruian who implemented a Twig tag, so you can use {% debug var %} instead of {{ debug(var) }}. For the moment, I've kept both syntax enabled, to gather more feedback before final decision,
  • https://github.com/nicolas-grekas/Patchwork-Dumper is up to date with these updates so you can test right now.

Positive and/or negative feedback welcomed!

@stloyd stloyd and 1 other commented on an outdated diff Apr 10, 2014
...nt/HttpKernel/DataCollector/VarDebugDataCollector.php
+ $excerpt = array();
+
+ for ($i = max($line - 3, 1), $max = min($line + 3, count($src)); $i <= $max; ++$i) {
+ $excerpt[] = '<li'.($i === $line ? ' class="selected"' : '').'><code>'.htmlspecialchars($src[$i - 1]).'</code></li>';
+ }
+
+ $excerpt = '<ol start="'.max($line - 3, 1).'">'.implode("\n", $excerpt).'</ol>';
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ $name or $name = 0 === strpos($file, $this->rootDir) ? substr($file, strlen($this->rootDir)) : $file;
@stloyd
stloyd added a note Apr 10, 2014

or => ||.

@stloyd
stloyd added a note Apr 10, 2014

In overall this line looks strange and unreadeable.

@stof
Symfony member
stof added a note Apr 10, 2014

@stloyd the change or to || would be wrong. This code here is using the control flow operator, not the boolean operator. Doing the change will even break the logic because of the different precedence of or and ||.
However, I agree that using a if would be more readable than using the control flow operator here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stloyd stloyd and 2 others commented on an outdated diff Apr 10, 2014
...nt/HttpKernel/DataCollector/VarDebugDataCollector.php
+ public function serialize()
+ {
+ $this->isCollected = true;
+
+ return parent::serialize();
+ }
+
+ public function __destruct()
+ {
+ if (!$this->isCollected) {
+ $this->isCollected = true;
+
+ $h = headers_list();
+ array_unshift($h, 'Content-Type: ' . ini_get('default_mimetype'));
+ $i = count($h);
+ while (0 !== stripos($h[--$i], 'Content-Type:')) {
@stloyd
stloyd added a note Apr 10, 2014

This loop does nothing...

@romainneutron
Symfony member

it decreases $i value

@stof
Symfony member
stof added a note Apr 10, 2014

I suggest adding a comment to make it clearer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Koc Koc commented on an outdated diff Apr 10, 2014
...fony/Component/VarDebug/Resources/functions/debug.php
+ /**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+ function debug($var)
+ {
+ static $reflector;
+
+ if (!isset($reflector)) {
+ $reflector = new ReflectionFunction('set_debug_handler');
+ }
+
+ $h = $reflector->getStaticVariables();
+
+ if (!isset($h['handler'])) {
+ if (class_exists('Symfony\Component\VarDebug\Dumper\CliDumper')) {
+ $collector = extension_loaded('symfony_debug') ? new ExtCollector : new PhpCollector;
@Koc
Koc added a note Apr 10, 2014

Symfony usually uses brackets for classes instanciation without args.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Koc

@nicolas-grekas nice, thanx. But it looks too complicated comparing to add just another function for inline dumping.

@pborreli pborreli commented on an outdated diff Apr 10, 2014
...nt/HttpKernel/DataCollector/VarDebugDataCollector.php
+class VarDebugDataCollector extends DataCollector
+{
+ private $rootDir;
+ private $stopwatch;
+ private $isCollected = true;
+
+ public function __construct($rootDir, Stopwatch $stopwatch = null)
+ {
+ $this->rootDir = dirname($rootDir).DIRECTORY_SEPARATOR;
+ $this->stopwatch = $stopwatch;
+ $this->data['dumps'] = array();
+ }
+
+ public function dump(Data $data)
+ {
+ $this->stopwatch and $this->stopwatch->start('debug');

and is never used in Symfony codebase, for readability, I would recommend a real test instead of this one line shortcut

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@tgabi333 tgabi333 commented on an outdated diff Apr 10, 2014
...ny/Component/VarDebug/Collector/AbstractCollector.php
+ 'r:gd' => 'Symfony\Component\VarDebug\Caster\BaseCaster::castGd',
+ 'r:mysql link' => 'Symfony\Component\VarDebug\Caster\BaseCaster::castMysqlLink',
+ 'r:process' => 'Symfony\Component\VarDebug\Caster\BaseCaster::castProcess',
+ 'r:stream' => 'Symfony\Component\VarDebug\Caster\BaseCaster::castStream',
+ );
+
+ protected $maxItems = 1000;
+ protected $maxString = 10000;
+
+ private $casters = array();
+ private $data = array(array(null));
+ private $prevErrorHandler = null;
+
+ public function __construct(array $defaultCasters = null)
+ {
+ isset($defaultCasters) or $defaultCasters = static::$defaultCasters;

For better readability and CS, please use an if statement here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 2 others commented on an outdated diff Apr 10, 2014
src/Symfony/Bridge/Twig/Node/DebugNode.php
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function compile(\Twig_Compiler $compiler)
+ {
+ if (!$this->env->isDebug()) {
+ return;
+ }
+
+ $compiler->addDebugInfo($this);
+ $compiler->write('debug(');
+ if (!$values = $this->getNode('values')) {
+ $compiler->raw('$context');
+ } elseif ($values->count() === 1) {
@stof
Symfony member
stof added a note Apr 10, 2014

$values is undefined here (which makes me think that this code is currently not tested)

$values is defined line 38

line 38 is an assignation in condition

@stof
Symfony member
stof added a note Apr 10, 2014

hmm sorry, missed it. I suggest moving the assignment outside the condition for readability

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
src/Symfony/Bridge/Twig/Node/DebugNode.php
+ {
+ if (!$this->env->isDebug()) {
+ return;
+ }
+
+ $compiler->addDebugInfo($this);
+ $compiler->write('debug(');
+ if (!$values = $this->getNode('values')) {
+ $compiler->raw('$context');
+ } elseif ($values->count() === 1) {
+ $compiler->subcompile($values->getNode(0));
+ } else {
+ $compiler->raw('array(');
+ foreach ($values as $node) {
+ if ($node->hasAttribute('name')) {
+ $compiler->raw("'".addslashes($node->getAttribute('name'))."' => ");
@stof
Symfony member
stof added a note Apr 10, 2014

you should use $compiler->string() instead of duplicating its logic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -54,6 +54,16 @@ public function boot()
if ($trustedHosts = $this->container->getParameter('kernel.trusted_hosts')) {
Request::setTrustedHosts($trustedHosts);
}
+
+ if (function_exists('set_debug_handler')) {
+ $container = $this->container;
+ $dumperService = 'cli' === PHP_SAPI ? 'var_debug.dumper.cli' : 'data_collector.var_debug';
+
+ set_debug_handler(function ($var) use ($container, $dumperService) {
+ $data = $container->get('var_debug.collector')->collect($var);
+ $container->get($dumperService)->dump($data);
+ });
+ }
@stof
Symfony member
stof added a note Apr 10, 2014

you also need to reset the debug handler on shutdown so that it does not keep a reference to the container preventing the garbage collection

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
src/Symfony/Component/VarDebug/Caster/BaseCaster.php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarDebug\Caster;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class BaseCaster
@stof
Symfony member
stof added a note Apr 10, 2014

BaseCaster seems to imply that other casters will extend from this class, which is not the case. A better name should be found. ResourceCaster is not good as it does not only deal with resources but also with closures and reflectors.
If someone has a good idea for a name, please comment with your suggestions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 2 others commented on an outdated diff Apr 10, 2014
src/Symfony/Component/VarDebug/Caster/DoctrineCaster.php
+namespace Symfony\Component\VarDebug\Caster;
+
+use Doctrine\Common\Proxy\Proxy as CommonProxy;
+use Doctrine\ORM\Proxy\Proxy as OrmProxy;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class DoctrineCaster
+{
+ public static function castCommonProxy(CommonProxy $p, array $a)
+ {
+ unset(
+ $a['__cloner__'],
+ $a['__initializer__'],
+ $a['__isInitialized__']
@stof
Symfony member
stof added a note Apr 10, 2014

I'm not sure we should remove this __isInitialized__ property entirely. It can make sense to know whether a proxy is initialized or no when debugging (for instance, some bugs may appear only before the initialization of the proxy, we already faced it)

@Koc
Koc added a note Apr 10, 2014

+1. Looks like it doesn't handle collections properly like in original dumper https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Util/Debug.php#L98

It does handle collections properly: the internal array will just be dumped as a private property of the ArrayCollection, which exactly represents the internal state of the collection. More over, if the collection is lazy, it won't trigger loading of the data, which is exactly what is required for debugging (no state change).

@stof
Symfony member
stof added a note Apr 10, 2014

for collections, the elements will appear (as the collection has the elements inside it), but it will also show you the other internal elements (useful to debug lazy collections for instance).
Thus, compared to the Doctrine dumper, it will not initialize lazy collection as a side effect of debugging them.

Note that the code available on Moday was including a caster for Doctrine Collection, but @nicolas-grekas and I decided to remove it when discussing about it during the hackday yesterday because of the reason above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff Apr 10, 2014
...Symfony/Component/VarDebug/Caster/ExceptionCaster.php
+ E_USER_NOTICE => 'E_USER_NOTICE',
+ E_STRICT => 'E_STRICT',
+ );
+
+ public static function castException(\Exception $e, array $a)
+ {
+ $trace = $a["\0Exception\0trace"];
+ unset($a["\0Exception\0trace"]); // Ensures the trace is always last
+
+ static::filterTrace($trace, static::$traceArgs);
+
+ if (isset($trace)) {
+ $a["\0Exception\0trace"] = $trace;
+ }
+ if (empty($a["\0Exception\0previous"])) {
+ unset($a["\0Exception\0previous"]);
@stof
Symfony member
stof added a note Apr 10, 2014

why removing the previous exception ?

Useless noise if it's empty

@stof
Symfony member
stof added a note Apr 10, 2014

hmm, I read it too fast. this is indeed fine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
...Symfony/Component/VarDebug/Caster/ExceptionCaster.php
+
+ empty($a["\0*\0message"]) and $a["\0*\0message"] = "Unexpected exception thrown from a caster: ".get_class($a["\0Exception\0previous"]);
+
+ isset($b["\0*\0message"]) and $a["\0~\0message"] = $b["\0*\0message"];
+ isset($b["\0*\0file"]) and $a["\0~\0file"] = $b["\0*\0file"];
+ isset($b["\0*\0line"]) and $a["\0~\0line"] = $b["\0*\0line"];
+ isset($b["\0Exception\0trace"]) and $a["\0~\0trace"] = $b["\0Exception\0trace"];
+
+ unset($a["\0Exception\0trace"], $a["\0Exception\0previous"], $a["\0*\0code"], $a["\0*\0file"], $a["\0*\0line"]);
+
+ return $a;
+ }
+
+ public static function filterTrace(&$trace, $dumpArgs, $offset = 0)
+ {
+ if (0 > $offset || empty($trace[$offset])) return $trace = null;
@stof
Symfony member
stof added a note Apr 10, 2014

please always use curly braces for control structures

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
src/Symfony/Component/VarDebug/Dumper/CliDumper.php
+ case '--color=never':
+ return false;
+ }
+ }
+ }
+ }
+
+ if (null !== static::$defaultColors) {
+ return static::$defaultColors;
+ }
+
+ if (empty($this->outputStream)) {
+ return false;
+ }
+
+ $colors = DIRECTORY_SEPARATOR === '\\'
@stof
Symfony member
stof added a note Apr 10, 2014

we generally use defined('PHP_WINDOWS_VERSION_MAJOR') (or one of the other windows-specific version constants) to detect windows

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
src/Symfony/Component/VarDebug/Dumper/HtmlDumper.php
+ $this->dumpPrefix = "<style>$s</style><pre class=$p style=white-space:pre>";
+ $this->dumpSuffix = '</pre>';
+ }
+
+ protected function style($style, $val)
+ {
+ if ('ref' === $style) {
+ $ref = substr($val, 1);
+ if ('#' === $val[0]) {
+ return "<a class=sf-var-debug-ref name=\"sf-var-debug-ref$ref\">$val</a>";
+ } else {
+ return "<a class=sf-var-debug-ref href=\"#sf-var-debug-ref$ref\">$val</a>";
+ }
+ }
+
+ $val = htmlspecialchars($val, ENT_NOQUOTES, 'UTF-8');
@stof
Symfony member
stof added a note Apr 10, 2014

why ENT_NOQUOTES ? We generally use ENT_QUOTES when escaping in Symfony

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff Apr 10, 2014
...fony/Component/VarDebug/Resources/functions/debug.php
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Component\VarDebug\Collector\ExtCollector;
+use Symfony\Component\VarDebug\Collector\PhpCollector;
+use Symfony\Component\VarDebug\Dumper\CliDumper;
+
+if (!function_exists('debug')) {
@stof
Symfony member
stof added a note Apr 10, 2014

when discussing during the hackday yesterday, we discovered a conflict with Drupal which also has a debug function. Yesterday evening, I had an idea to workaround this issue (yeah, my brain keeps computing things at time I go to bed):
I suggest moving this logic to a namepsaced class with 2 static methods (it will also avoid using reflection to access the debug handler). then, the debug function defined conditionally would just be a wrapper around Symfony\Component\VarDebug\VarDebug::debug() (or whatever the class name is). This way, if you have a conflicting function in your codebase (i.e. Drupal for instance), you can still use the VarDebug component without copy-pasting the logic. You simply need to use the static method directly (or to define your own wrapper shortcut with a different name).
If we go this way, the Twig integration should call the static method directly to be compatible with cases where the shortcut wrapper is not available.
For set_debug_handler, we can then either drop it entirely or build it as a wrapper around the static method.

@romainneutron
Symfony member

👍 for Symfony\Component\VarDebug\VarDebug::debug()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
...fony/Component/VarDebug/Resources/functions/debug.php
+ if (class_exists('Symfony\Component\VarDebug\Dumper\CliDumper')) {
+ $collector = extension_loaded('symfony_debug') ? new ExtCollector : new PhpCollector;
+ $dumper = new CliDumper;
+ $h['handler'] = function ($var) use ($collector, $dumper) {
+ $dumper->dump($collector->collect($var));
+ };
+ } else {
+ $h['handler'] = 'var_dump';
+ }
+ set_debug_handler($h['handler']);
+ }
+
+ return $h['handler']($var);
+ }
+
+ function set_debug_handler($callable)
@stof
Symfony member
stof added a note Apr 10, 2014

the code is currently handling the case of debug existing already, but it does not check set_debug_handler, which can create some issues (it will be solved by my suggestion above though)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 3 others commented on an outdated diff Apr 10, 2014
...fony/Component/VarDebug/Resources/functions/debug.php
+ $h = $reflector->getStaticVariables();
+
+ if (!isset($h['handler'])) {
+ if (class_exists('Symfony\Component\VarDebug\Dumper\CliDumper')) {
+ $collector = extension_loaded('symfony_debug') ? new ExtCollector : new PhpCollector;
+ $dumper = new CliDumper;
+ $h['handler'] = function ($var) use ($collector, $dumper) {
+ $dumper->dump($collector->collect($var));
+ };
+ } else {
+ $h['handler'] = 'var_dump';
+ }
+ set_debug_handler($h['handler']);
+ }
+
+ return $h['handler']($var);
@stof
Symfony member
stof added a note Apr 10, 2014

this syntax is not compatible with PHP 5.3 when using array($object, $method) for the callable. call_user_func need to be used (PHP 5.4+ handles it fine)

It works since PHP4.3.0 :)
http://3v4l.org/qiBkL

@stof
Symfony member
stof added a note Apr 10, 2014

nope. your handler is a function name, which is not the case I described in my comment. See http://3v4l.org/cZHfs for the actual testcase

@romainneutron
Symfony member

stof means that the following code does not work:

class a {
    function b() {
        $handler = array($this, 'hello');
        $handler('nicolas');
    }

    function hello($var) {
        echo 'hello '.$var;
    }
}

$a = new a();
$a->b();
@Taluu
Taluu added a note Apr 10, 2014

@romainneutron & @stof sure your points are valid... But here, it is either an anonymous function, either a string, which works in 5.3.

But as you can't control the form of $h['handler'], as it may be an array, described by @stof (and @romainneutron), you should use the call_user_func, as ugly as that is.

Ok understood! That's one of the reason why I previously accepted only closures...

@stof
Symfony member
stof added a note Apr 10, 2014

@nicolas-grekas in Symfony, we prefer giving more flexibility to the caller and taking care of this unfortunate limitation of PHP 5.3 internally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
src/Symfony/Component/VarDebug/Caster/PdoCaster.php
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarDebug\Caster;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class PdoCaster
+{
+ public static $pdoAttributes = array(
@stof
Symfony member
stof added a note Apr 10, 2014

this array should be private, or keys should be validated before using constant("PDO::ATTR_{$attr}") to avoid fatal errors because of undefined constants. If the array is public, we cannot ensure that other keys are not added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 2 others commented on an outdated diff Apr 10, 2014
src/Symfony/Component/VarDebug/Caster/SplCaster.php
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarDebug\Caster;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class SplCaster
+{
+ public static function castIterator(\Iterator $c, array $a)
+ {
+ $a = array_merge($a, iterator_to_array($c));
@stof
Symfony member
stof added a note Apr 10, 2014

this can have side effects:

  • some iterators can be iterated only once (NoRewindIterator and generators for instance, or PDOStatement according to a recent discussion in the Twig mailing list)
  • some iterators are lazy, and will be initialized
  • if you build an infinite iterator (expecting to wrap it in a LimitIterator later or to break the loop explicitly), calling iterator_to_array on it will be an infinite loop. the SPL even has an InfiniteIterator class looping over an iterator forever

Right!
This is why this caster is not binded to all iterators,
but only to SplHeap and SplPriorityQueue,
see https://github.com/symfony/symfony/pull/10640/files#diff-0c6211bd36b3e57a58b75d9cbeeb2e20R38

@stof
Symfony member
stof added a note Apr 10, 2014

maybe the method should be renamed then, to avoid confusion

@stof
Symfony member
stof added a note Apr 10, 2014

iterating over a SplPriorityQueue actually also have side effects: it removes elements during the iteration

@stof
Symfony member
stof added a note Apr 10, 2014

proof is at http://3v4l.org/8ofUT

iterator_to_array(clone $c) ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
src/Symfony/Bridge/Twig/Node/DebugNode.php
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\Twig\Node;
+
+/**
+ * @author Julien Galenski <julien.galenski@gmail.com>
+ */
+class DebugNode extends \Twig_Node
+{
+ protected $env;
@stof
Symfony member
stof added a note Apr 10, 2014

should be private

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
src/Symfony/Bridge/Twig/Node/DebugNode.php
+class DebugNode extends \Twig_Node
+{
+ protected $env;
+
+ public function __construct(\Twig_Environment $env, \Twig_NodeInterface $values = null, $lineno = 0, $tag = null)
+ {
+ parent::__construct(array('values' => $values), array(), $lineno, $tag);
+ $this->env = $env;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function compile(\Twig_Compiler $compiler)
+ {
+ if (!$this->env->isDebug()) {
@stof
Symfony member
stof added a note Apr 10, 2014

Twig does not vary the cache based on the debug mode. So this needs to be checked at render time, not at compile time.
See https://github.com/fabpot/Twig-extensions/blob/master/lib/Twig/Extensions/Node/Debug.php for an example in the Twig deprecated debug tag

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
...Symfony/Component/VarDebug/Collector/ExtCollector.php
+ $r = (object) array('count' => $zval['array_count']);
+ $arrayRefs[$len] = $r;
+ $a = $v;
+ }
+ break;
+
+ case 'object':
+ if (empty($softRefs[$h = $zval['object_hash']])) {
+ $r = $softRefs[$h] = (object) array('class' => $zval['object_class']);
+ if (0 >= $maxItems || $pos < $maxItems) {
+ $a = $this->castObject($r->class, $v);
+ } else {
+ $r->cut = -1;
+ }
+ } else {
+ $r = $softRefs[$h];
@stof
Symfony member
stof added a note Apr 10, 2014

@nicolas-grekas could you use longer variable names for all these local variables, based on their meaning ? This will make the code much more readable.
We are not in minified JS code where each byte saved in the file size is a win. Readability is key (especially for such tricky logic)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof and 1 other commented on an outdated diff Apr 10, 2014
...Symfony/Component/VarDebug/Collector/PhpCollector.php
+ unset($r);
+ if ($v instanceof \stdClass && isset($hardRefs[spl_object_hash($v)])) {
+ $v->ref = ++$refs;
+ $step[$k] = $queue[$i][$k] = $v;
+ continue;
+ }
+ $isRef = true;
+ }
+ switch (gettype($v)) {
+ case 'string':
+ if (isset($v[0]) && !preg_match('//u', $v)) {
+ if (0 < $maxString && 0 < $cut = strlen($v) - $maxString) {
+ $r = substr_replace($v, '', 0, $maxString - 1);
+ $r = (object) array('cut' => $cut + 1, 'bin' => iconv('CP1252', 'UTF-8', $r));
+ } else {
+ $r = (object) array('bin' => iconv('CP1252', 'UTF-8', $v));
@stof
Symfony member
stof added a note Apr 10, 2014

Symfony does not have a strict dependency on iconv currently. so you need to check whether it is available (Symfony generally tries using both iconv and mb_convert_encoding as you can have 1 extension without having the other one)

I understand for mbstring, but iconv... it is enabled by default in PHP:
http://php.net/manual/en/iconv.installation.php
I'll work around this thanks for the notice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
...undle/Tests/DependencyInjection/ConfigurationTest.php
@@ -139,6 +139,10 @@ protected static function getBundleDefaultConfig()
'serializer' => array(
'enabled' => false
)
@stof
Symfony member
stof added a note Apr 10, 2014

syntax error here. The comma is missing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff Apr 10, 2014
...undle/Tests/DependencyInjection/ConfigurationTest.php
@@ -139,6 +139,10 @@ protected static function getBundleDefaultConfig()
'serializer' => array(
'enabled' => false
)
+ 'var_debug' => array(
+ 'max_items' => 1000,
+ 'max_string' => 10000,
+ )
@stof
Symfony member
stof added a note Apr 10, 2014

please add the trailing comma here, to avoid the same bug next time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@nicolas-grekas

@stof thanks for your review!
Do you see anything else for the todo above?
Anyone else?

@lyrixx

@nicolas-grekas can you past some screen-shots (especially the icon ;))

@Tobion
Symfony member

Can we not merge the "VarDebug" and "Debug" component? I find it rather strange to have 2 components with almost identical naming and semantic.

@nicolas-grekas

For comments in the extension folder, @jpauli wants to keep them for future enhancement.
About the proposition of a debug_collect() function, I prefer not: the cognitive cost of requiring every dev to choose daily between debug() vs debug_collect() is far higher than writing a generic code that frees devs from even learning about the subject and then afterwards deciding which version should be used in this or that context.

Do someone use debug() now? How do you feel about it?

@romainneutron
Symfony member

Note: to test this component in your project, simply run

composer require patchwork/dumper:~1.1
@Tobion Tobion commented on an outdated diff Apr 18, 2014
src/Symfony/Component/VarDebug/VarDebug.php
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\VarDebug;
+
+use Symfony\Component\VarDebug\Collector\ExtCollector;
+use Symfony\Component\VarDebug\Collector\PhpCollector;
+use Symfony\Component\VarDebug\Dumper\CliDumper;
+use Symfony\Component\VarDebug\Dumper\HtmlDumper;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class VarDebug
+{
+ private static $handlerObject;
@Tobion
Symfony member
Tobion added a note Apr 18, 2014

typo: the implementation uses objectHandler. handlerObject is probably the better naming

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@umpirsky

Any reason why this is not part of Debug component?

@nicolas-grekas

Currently, we have three main namespaces:

  • VarDebug\Caster
  • VarDebug\Collector
  • VarDebug\Dumper

Merging with Debug component could mean moving to:

  • Debug\VarCaster
  • Debug\VarCollector
  • Debug\VarDumper

Anyone with better name ideas?

@Taluu

How about using a "Var" namespace, inside the Debug component ?

@stof
Symfony member

@nicolas-grekas Actually, if we move to the Debug component, it would make more sense to have all this avr debugging in a single subnamespace of the component, like we did for Config\Definition and Config\Loader.

However, I'm -1 for such move. Putting several independant features in the same component hurts the proper definition of dependencies for other libraries. We suffer of it for the Config definition for instance.
And this would go against the current move of Symfony:

  • the security component was split into 3 components in 2.4 (this was easy as it was already organized as 3 subnamespaces), with symfony/security replacing them all.
  • there is a WIP about extracting the profiler from HttpKernel for Symfony 2.6 to make HttpKernel smaller (and more splitting work in the 3.0 roadmap)

Splitting a component by moving code to a new location is a pain to preserve BC, so I would prefer keeping it as a new component from the start

@Taluu

Mmh, true, forgot about that. Then how about "Dumper" ? As it comes from "Patchwrok-Dumper" anyway..

@nicolas-grekas

Agree with @stof especially since code here has no technical relationship with Debug component. That's also my rational for a new component.

@umpirsky

I would at least like to come up with better name for this component, but nothing comes to my mind.

@Tobion
Symfony member

I agree having individual components makes sense when they are not related. But having a component named "Debug" and another "VarDebug" is pretty silly for a user who doesn't know the details, it's like having "WebBrowser" and "Browser" components.

@pyrech

Agreed with @umpirsky and @Tobion. And as @Taluu, I find Dumper is a good name for this component.

@umpirsky

Maybe it should be named Dump.

@nicolas-grekas

Let's find a better name.
Here are some though:

Even if it will be first used for that, the code in VarDebug is not technically related to debugging.
What the code really does is implementing an algorithm that creates a deep copy of any PHP variable, with casters for extracting data/metadata from objects/resources and a limiter to stop copying too heavy structures. Dumping is for me only one possible use of this copy, with more to be invented if that applies to some problem.

So, "VarDumper" might be better than "VarDebug", but IMHO it would still be too much a description of the intended use of the code rather than what it does in itself.

What do you think of these arguments?

Any love for VarFrezzer? VarSnapshotter? VarFacsimile? VarCopier?

@nicolas-grekas

What about Symfony\Component\VarDump? I prefer it over VarDebug, and can't find better... Anyone else?

@Taluu

This is a bit better, but having Var as a prefix is kinda troublesome I think, and will lead to confusion (and isn't it the same as Dumper anyway ?). If its goal is to extract the information contained in the variable (or something else if we extend the possibilities), why not Extractor or something like that then ?

@nicolas-grekas

Not "Dumper", because in Symfony we have many dumpers: a container dumper, a class map dumper, a route dumper, a data collector dumper, a yaml dumper, etc.
So VarDump, because this dumps vars :)
An other idea: Repr, modeled after python repr, which is how they call their var_dump (but then, let's stay PHPish and call it VarDump again?)
If we agree that VarDump is better than VarDebug, I propose changing now, until an even better alternative is found?

@nicolas-grekas nicolas-grekas changed the title from VarDebug component to [WIP] VarDumper and DebugBundle May 28, 2014
@nicolas-grekas

Just to let you know that this PR might be in a merge-able state by the end of the week or the week after:
I updated the TODO above. For the naming concern, after talking with some of you, I refactored the code around a new VarDumper component that holds all the dumping logic, and a new DebugBundle that holds all the Symfony required glue. After merging this PR, most debug related concerns that are currently scattered in other bundles/components could be put together in the new bundle.

Remaining todos are:

  • integrate with FrameworkBundle / Standard edition
  • tests for the DebugBundle
@lyrixx

IMHO, the twig part could be move the a bridge to be able to re-use it in silex and drupal and ...

@lyrixx

IIRC, The twig tag does not output the value in the HTML. But I think we need something for that.
Use case: The controller give you an array, you just want to dump it to see what value you can use. And you want everything in the same place. I mean, I don't want to open a new tab to do that. WDYT?

@stof
Symfony member

@lyrixx the purpose of this dumper is precisely to avoid putting the dump in the HTML, which tends to break it. Putting the dump in the HTML is already possible with var_dump, which can be used in Twig.

@lyrixx

@stof Thanks. But I know ;) I think the new component is more powerful than var_dump, so I could prefer to use the new tag / function than debug (and not var_dump ;))

@nicolas-grekas

Do you ever sleep guys?
BTW, I came up with an other use case of VarDumper yesterday: unit testing.
I wrote an assertion that verifies that some structure is correct according to its expected dump.
A lot easier to check and still accurate. Works well with phpunit's strings diff on failure also.
Generalizing this use case would need a dumper with a guaranteed stable output format.

@hice3000

Ever thought about time lag? :D
BTW: Using this for unit testing is a great example of this components usefulness.

@nicolas-grekas

@lyrixx a dump excerpt is displayed on hovering the "debug()" icon toolbar. This still preserves the original HTML and prevents extra jumps/clicks to the "debug()" panel. The excerpt is very short currently, but we can work on making it more useful if what is currently displayed is not enough (btw, I suggest postponing these enhancements until this PR is merged).

@jderusse jderusse commented on an outdated diff Aug 26, 2014
...undle/Resources/views/Profiler/OwlyCode/debug.js.twig
+
+ if (typeof(value) == "string" && value.indexOf('b`') != -1) {
+ var position = value.indexOf('b`');
+ if (position !== 0) {
+ __self.cut = parseInt(value.substr(0, position));
+ }
+ __self.utf8 = false;
+ value = value.substr(position+2, value.length);
+ }
+
+ if (typeof(value) == "string" && value.indexOf('u`') != -1) {
+ var position = value.indexOf('u`');
+ if (position !== 0) {
+ __self.cut = parseInt(value.substr(0, position));
+ }
+ value = value.substr(position + 2, value.length);

value = value.substr(position+2);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jderusse jderusse commented on an outdated diff Aug 26, 2014
...ndle/Resources/views/Profiler/Patchwork/debug.js.twig
+ title.push('Empty string');
+ push('', 'string empty' + tags, title);
+ return;
+ }
+
+ i = data.indexOf('`');
+ if (-1 == i) data = ['u', data];
+ else data = [data.substr(0, i), data.substr(i+1)];
+ i = data[0].charAt(data[0].length - 1);
+
+ switch (i)
+ {
+ case 'R':
+ case 'r': return;
+ case 'n': push(data[1], 'const' + tags, title); return;
+ case 'b': tags += ' bin'; title.push('Binary');

Looks like break is missing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@johnkary johnkary and 1 other commented on an outdated diff Aug 27, 2014
...ponent/HttpKernel/DataCollector/DumpDataCollector.php
+use Symfony\Component\VarDumper\Dumper\JsonDumper;
+use Symfony\Component\VarDumper\Dumper\CliDumper;
+use Symfony\Component\VarDumper\Dumper\HtmlDumper;
+use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ */
+class DumpDataCollector extends DataCollector implements DataDumperInterface
+{
+ private $stopwatch;
+ private $isCollected = true;
+ private $clonesRoot;
+ private $clonesCount = 0;
+
+ public function __construct(Stopwatch $stopwatch = null)

This DumpDataCollector class would be part of the HttpKernel component. By hinting for Stopwatch doesn't this create a (new) required dependency of symfony/http-kernel on symfony/stopwatch?

Ah, no it doesn't. DumpDataCollector would only be used when installing dev dependencies, which symfony/http-kernel has require-dev for symfony/stopwatch.

@stof
Symfony member
stof added a note Aug 27, 2014

@johnkary a typehint does not introduce a dependency. the dependency is needed for the object implementing this typehint. Checking a typehint just looks at the object being passed.
and given the parameter is nullable, there is no hard dependency (if you don't have the stopwatch component, you simply need to pass null).

checking typehints works exactly the same than instanceof checks: they don't require the class to exist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@nicolas-grekas nicolas-grekas added the DX label Aug 27, 2014
@nicolas-grekas

Comments addressed or answered, I also added tests for the Twig extension and for the DebugBundle extension. I still have to prefix the CSS classes, and write a test for the data collector and an other one for the even listener.

@hhamon

Hi Nico! You were asking people for a better name for your component, I was thinking of VarInspector.

@nicolas-grekas

Notice the "nodeType" property and how child objects are displayed

dump():
capture du 2014-09-09 11 23 26

VS var_dump():

capture du 2014-09-09 11 31 44

@nicolas-grekas nicolas-grekas changed the title from [RFR] VarDumper and DebugBundle to VarDumper and DebugBundle Sep 10, 2014
@nicolas-grekas

ping @symfony/deciders :
I addressed all remaining technical points: mainly adding tests and prefixes to CSS.
I also refactored a bit the resources related to the profiler panel,
and added a feature for better cutting while dumping.
Except for the doc PR I still have to open, this is ready for merge on my side.
Can you please vote and/or tell me if you see anything that could block a merge before 2.6 is frozen?
Many thanks

@nicolas-grekas nicolas-grekas referenced this pull request in symfony/symfony-standard Sep 12, 2014
Merged

Enable DebugBundle #710

@fabpot fabpot and 2 others commented on an outdated diff Sep 15, 2014
composer.json
@@ -83,7 +85,10 @@
"src/Symfony/Component/HttpFoundation/Resources/stubs",
"src/Symfony/Component/Intl/Resources/stubs"
],
- "files": [ "src/Symfony/Component/Intl/Resources/stubs/functions.php" ]
+ "files": [
+ "src/Symfony/Component/Intl/Resources/stubs/functions.php",
+ "src/Symfony/Component/VarDumper/Resources/functions/dump.php"
@fabpot
Symfony member
fabpot added a note Sep 15, 2014

I'm not comfortable adding yet another file here.

I'll look how I could inline the function somewhere instead (bootstrap.cache.php?), it's only a few lines.

@kbond
kbond added a note Sep 16, 2014

not sure that bootstrap.cache.php is the best place as not everyone uses it. ref: http://symfony.com/doc/current/book/performance.html#bootstrap-files-and-byte-code-caches

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@fabpot fabpot commented on the diff Sep 15, 2014
src/Symfony/Bridge/Twig/TokenParser/DumpTokenParser.php
+ {
+ $values = null;
+ if (!$this->parser->getStream()->test(\Twig_Token::BLOCK_END_TYPE)) {
+ $values = $this->parser->getExpressionParser()->parseMultitargetExpression();
+ }
+ $this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE);
+
+ return new DumpNode($this->parser->getVarName(), $values, $token->getLine(), $this->getTag());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTag()
+ {
+ return 'dump';
@fabpot
Symfony member
fabpot added a note Sep 15, 2014

We already have a dump function in Twig, so this one is confusing.

What about replacing the existing dump function also? Using the tag would feed the profiler panel, and using the function would do the same as the current dump function: inline dump of vars, with a better output format.

@fabpot
Symfony member
fabpot added a note Sep 16, 2014

sounds like a good idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@fabpot fabpot commented on an outdated diff Sep 15, 2014
src/Symfony/Bundle/DebugBundle/README.md
+- per object and resource types specialized view: e.g. filter out Doctrine noise
+ while dumping a single proxy entity, or get more insight on opened files with
+ `stream_get_meta_data()`. Add your own dedicated `Dumper\Caster` and get the
+ view *you* need.
+- configurable output format: HTML, command line with colors or [a dedicated high
+ accuracy JSON format](Resource/doc/json-spec.md).
+ More to come / add your own.
+- ability to dump internal references, either soft ones (objects or resources)
+ or hard ones (`=&` on arrays or objects properties). Repeated occurrences of
+ the same object/array/resource won't appear again and again anymore. Moreover,
+ you'll be able to inspected the reference structure of your data.
+- ability to operate in the context of an output buffering handler.
+- full exposure of the internal mechanisms used for walking through an arbitrary
+ PHP data structure.
+
+Calling `dump($myVvar)` works in all PHP code and `{% dump myVar %}` in Twig templates.
@fabpot
Symfony member
fabpot added a note Sep 15, 2014

For this to work, the user must require the file where the dump() function is defined as the file is not automatically loaded in the composer.json of the component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@nicolas-grekas nicolas-grekas commented on the diff Sep 15, 2014
src/Symfony/Component/VarDumper/composer.json
+ "homepage": "http://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-symfony_debug": ""
+ },
+ "autoload": {
+ "files": [ "Resources/functions/dump.php" ],

Does this line address your comment on the readme @fabpot?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@nicolas-grekas

I moved the auto-required file to an inline in the standard-edition: https://github.com/symfony/symfony-standard/pull/710/files
I also opened a doc PR: symfony/symfony-docs#4243
And I added a dump() function in Twig.
This is all green on my side.

@xabbuh xabbuh referenced this pull request in symfony/symfony-docs Sep 17, 2014
Merged

[WIP] var-dumper component #4243

6 of 6 tasks complete
@cordoval cordoval commented on an outdated diff Sep 18, 2014
...dle/DebugBundle/DependencyInjection/Configuration.php
+ $rootNode = $treeBuilder->root('debug');
+
+ $rootNode
+ ->children()
+ ->integerNode('max_items')
+ ->info('Max number of displayed items past the first level, -1 means no limit')
+ ->min(-1)
+ ->defaultValue(250)
+ ->end()
+ ->integerNode('max_string_length')
+ ->info('Max length of displayed strings, -1 means no limit')
+ ->min(-1)
+ ->defaultValue(-1)
+ ->end()
+ ->scalarNode('profiler_template')
+ ->info('The template used for theming the debub panel in the profiler')

debug typo: debub -> debug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on an outdated diff Sep 18, 2014
...dle/DebugBundle/DependencyInjection/Configuration.php
+ ->children()
+ ->integerNode('max_items')
+ ->info('Max number of displayed items past the first level, -1 means no limit')
+ ->min(-1)
+ ->defaultValue(250)
+ ->end()
+ ->integerNode('max_string_length')
+ ->info('Max length of displayed strings, -1 means no limit')
+ ->min(-1)
+ ->defaultValue(-1)
+ ->end()
+ ->scalarNode('profiler_template')
+ ->info('The template used for theming the debub panel in the profiler')
+ ->defaultValue('@Debug/Profiler/Patchwork/dump.html.twig')
+ ->end()
+ ->end();

put the ; on the next line aligned to the start of the $rootNode->

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on an outdated diff Sep 18, 2014
src/Symfony/Bundle/DebugBundle/README.md
@@ -0,0 +1,23 @@
+dump() function
+================
+
+This bundle provides a better `dump()` function, that you can use instead of
+`var_dump()`, *better* being for:
*better* meaning:

or

by *better* meaning:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on the diff Sep 18, 2014
src/Symfony/Bundle/DebugBundle/README.md
@@ -0,0 +1,23 @@
+dump() function
+================
+
+This bundle provides a better `dump()` function, that you can use instead of
+`var_dump()`, *better* being for:
+
+- per object and resource types specialized view: e.g. filter out Doctrine noise
+ while dumping a single proxy entity, or get more insight on opened files with
+ `stream_get_meta_data()`. Add your own dedicated `Dumper\Caster` and get the
+ view *you* need.
+- configurable output format: HTML, command line with colors or [a dedicated high

or goes inside the []

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on an outdated diff Sep 18, 2014
src/Symfony/Bundle/DebugBundle/README.md
@@ -0,0 +1,23 @@
+dump() function
+================
+
+This bundle provides a better `dump()` function, that you can use instead of
+`var_dump()`, *better* being for:
+
+- per object and resource types specialized view: e.g. filter out Doctrine noise
+ while dumping a single proxy entity, or get more insight on opened files with
+ `stream_get_meta_data()`. Add your own dedicated `Dumper\Caster` and get the
+ view *you* need.
+- configurable output format: HTML, command line with colors or [a dedicated high
+ accuracy JSON format](Resource/doc/json-spec.md).
+ More to come / add your own.

this is not very clear

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on an outdated diff Sep 18, 2014
src/Symfony/Bundle/DebugBundle/README.md
+================
+
+This bundle provides a better `dump()` function, that you can use instead of
+`var_dump()`, *better* being for:
+
+- per object and resource types specialized view: e.g. filter out Doctrine noise
+ while dumping a single proxy entity, or get more insight on opened files with
+ `stream_get_meta_data()`. Add your own dedicated `Dumper\Caster` and get the
+ view *you* need.
+- configurable output format: HTML, command line with colors or [a dedicated high
+ accuracy JSON format](Resource/doc/json-spec.md).
+ More to come / add your own.
+- ability to dump internal references, either soft ones (objects or resources)
+ or hard ones (`=&` on arrays or objects properties). Repeated occurrences of
+ the same object/array/resource won't appear again and again anymore. Moreover,
+ you'll be able to inspected the reference structure of your data.

to inspect is not conjugated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on an outdated diff Sep 18, 2014
...ugBundle/Resources/views/Profiler/Base/dump.html.twig
+
+{% block toolbar %}
+ {% set dumps_count = collector.dumpsCount %}
+
+ {% if dumps_count %}
+ {% set icon %}
+ <img alt="dump()" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAcCAYAAACOGPReAAACcUlEQVRIx+1UPUwUYRB97+Pc8ychMSaE4E+BrYWVgCd7e5dYQSxoiIFEjYWVdNiJiVjaSGFhowUkhsLEH2Jhcvsd54nYaQ0USoAYG7WBvWOfhd+R87zFC40N00z2zTdv30xmBti3/2ZBECy3+pZJgXw+f0rSiKQBkt2SOkluSFoh+SqKoplyufylJdIgCNIAJgGMkUzXcEkAEJM0DtqUNAVgwlq7Vc9hGtR1ACiSHCeZlvQGwFClUjkKYAVAexzHFyXNAkiTvEXSury/lTqFRZI9kr4DuGKtfV6L53K5tTAMu+reZwDMkuwC8F5SUFNcr3TSEf4g6dcTuvIP139ba8vGmD5JawB6Adz9o/xMJnMSwJhLvhGG4acm/T/UCBQKhc9xHA8DAMkxx/Ob1PO8UdfDD8Vi8WnCQAw1A+fn599KegbgoOd5Izukkgbc354kjZi1di4pJumx84M7pCRPO/DdXhaD5ILz3QDAXC4XATiQ8H48DMP7jWA2mx00xrxMUB3Rjcs6gE5JZ621H/ewwsdIfgOwHoZhV22klpz883spX1Kf80v1czrnwKtJidlsdnCXnl6r5zEAUK1WpwFskjwXBMFws8SkHvq+f4HkEIDN7e3tmR3SUqm06o4DADzyff9MK2X39/efMMbU5vpBqVRabVzTCUmLJNvb2tpKu5XrFPamUqkFksfd7t9pevry+XxHHMcvSPa4Hr+W9LBarVrP836mUqkjlUqlF8B1kpcBUNKiMeZSoVD4+q97eg/Azdo9lRSTNDXvsC0AUwBuN97TXS9/HMejAAbcpnQC2JC0THIuiqLppMvfsrnN27d/2y+hkCBqr75LOwAAAABJRU5ErkJggg==" />
+ <span class="sf-toolbar-status sf-toolbar-status-yellow">{{ dumps_count }}</span>
+ {% endset %}
+
+ {% set text %}
+ <div class="sf-toolbar-info-piece">
+ <b>dump()</b>
+ </div>
+ {% for dump in collector.getDumps('html', 1, 3) %}
+ <div class="sf-toolbar-info-piece">

can we indent this one more level?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on the diff Sep 18, 2014
src/Symfony/Component/Debug/Resources/ext/README.rst
+ 'strlen' => strlen($array[$key]),
+ );
+ break;
+ }
+
+ return $info;
+ }
+
+To enable the extension from source, run:
+
+.. code-block:: sh
+
+ phpize
+ ./configure
+ make
+ sudo make install

i wonder if these extensions including twig are easy installable like brew install php56-symfony-debug or such, could we should have a note perhaps on the documentation if it is not there already?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on an outdated diff Sep 18, 2014
src/Symfony/Component/VarDumper/README.md
@@ -0,0 +1,14 @@
+Symfony mechanim for exploring and dumping PHP variables

mechanism

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@cordoval cordoval commented on an outdated diff Sep 18, 2014
src/Symfony/Component/VarDumper/README.md
@@ -0,0 +1,14 @@
+Symfony mechanim for exploring and dumping PHP variables
+========================================================
+
+This component provides a mechanism that allows exploring then dumping
+any PHP variable.
+
+It handles scalar, objects and resources properly, taking hard and soft

scalars

Sign up for free to join this conversat