Компонент VarDumper (сброс переменной)

Дата обновления перевода 2024-07-12

Компонент VarDumper (сброс переменной)

Компонент VarDumper предоставляет механизмы для извлечения состояния из любой переменной PHP. Так как он надстраивается, он предоставляет улучшенную функцию dump(), которую вы можете использовать вместо var_dump.

Установка

1
$ composer require symfony/var-dumper --dev

Note

Если вы устанавливаете этот компонент вне приложения Symfony, вам нужно подключить файл vendor/autoload.php в вашем коде для включения механизма автозагрузки классов, предоставляемых Composer. Детальнее читайте в этой статье.

Note

Если вы используете его внутри приложения Symfony, убедитесь, что был установлен DebugBundle (или запустите composer require --dev symfony/debug-bundle, чтобы установить его).

Функция dump()

Компонент VarDumper создаёт глобальную функцию dump(), которую вы можете использовать вместо, например. var_dump. Используя её, вы получаете:

  • Специализированный просмотр по объектам и источникам, чтобы, к примеру, отфильтровать внутренние объекты Doctrine при сбросе одной сущности прокси, или получить больше информации об открытых с помощью stream_get_meta_data файлах;
  • Конфигурируемые форматы вывода: вывод HTML или цветной командной строки;
  • Возможность сбрасывать внутренние ссылки, мягкие (объекты или источники) или жёсткие (=& в свойствах массивов или объектов). Повторяемое появление одного и того же объекта/масива/истоничка не будут больше появляться снова и снова. Более того, вы сможете исследовать структуру ссылок ваших данных;
  • Возможность оперировать в контексте обработчика буферизации вывода.

Например:

1
2
3
4
5
6
7
8
9
require __DIR__.'/vendor/autoload.php';

// создать переменную, которая может быть чем угодно!
$someVar = ...;

dump($someVar);

// dump() возвращает переданное значение, чтобы вы могли сбросить объект и продолжать использовать его
dump($someObject)->someMethod();

По умолчанию, формат вывода и направление выбираются исходя из вашего текущего PHP SAPI:

  • В командной строке (CLI SAPI), вывод пишется в STDOUT. Это может быть удивительно для некоторых, так как это обходит механизм буферизации вывода PHP;
  • В других SAPI, сбросы пишутся в виде HTML в обычном выводе.

Tip

Вы также можете выбрать формат вывода ясно, определив переменную окружения VAR_DUMPER_FORMAT и установив её значение как html, cli или сервер .

Note

Если вы хотите поймать вывод сброса в виде строки, пожалуйста, прочтите продвинутую документацию, которая содержит такие примеры. Вы также узнаете, как изменять формат или перенаправлять вывод туда, куда вам нужно.

Tip

Для того, чтобы функция dump() всегда была доступна при выполнении любого PHP кода, вы можете установить её на вашем компьютере глобально:

  1. Запустите composer global require symfony/var-dumper;
  2. Добавьте auto_prepend_file = ${HOME}/.composer/vendor/autoload.php к вашему файлу php.ini;
  3. Иногда запускайте composer global update symfony/var-dumper, чтобы иметь последние исправления багов.

Tip

Компонент VarDumper также предоставляет функцию dd() ("dump and die" - "сбрось и умри"). Эта функция отображает переменные используя dump() и сразу прекращает исполнение скрипта (используя функцию PHP exit).

Сервер сброса

Функция dump() выводит своё содержание в то же окно браузера или консольный терминал, что и ваше приложение. Иногда смешение настоящего вывода с выводом отладочной информации может запутывать. Поэтому этот компонент предоставляет сервер для сбора всей отладочной информации.

Запустите сервер командой server:dump и когда вы будете вызывать dump(), отладочная информация не будет отображаться в потоке вывода, а отправится на этот сервер, который будет отображать это в своей конслоли или HTML-файле:

1
2
3
4
5
6
# отображает отладочную информацию в консоли:
$ ./bin/console server:dump
  [OK] Server listening on tcp://0.0.0.0:9912

# сохраняет отладочную информацию в файле используя формат HTML:
$ ./bin/console server:dump --format=html > dump.html

Внути приложения Symfony, вывод сервера сброса настраивается с помощью настройки dump_destination пакета debug:

1
2
3
# config/packages/debug.yaml
debug:
   dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"

Вне приложения Symfony, используйте класс ServerDumper:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\ContextProvider\CliContextProvider;
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\Dumper\ServerDumper;
use Symfony\Component\VarDumper\VarDumper;

$cloner = new VarCloner();
$fallbackDumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg']) ? new CliDumper() : new HtmlDumper();
$dumper = new ServerDumper('tcp://127.0.0.1:9912', $fallbackDumper, [
    'cli' => new CliContextProvider(),
    'source' => new SourceContextProvider(),
]);

VarDumper::setHandler(function (mixed $var) use ($cloner, $dumper): ?string {
    $dumper->dump($cloner->cloneVar($var));
});

Note

Второй аргумент ServerDumper - это класс экземпляра DataDumperInterface, используемый в качестве резерва, когда сервер недоступен. Третий аргумент - это поставщики контекста, которые позволяют собрать некоторую информацию о контексте, в котором были сброшены данные. Встроенные поставщики контекста: cli, request и source.

Затем вы можете использовать следующую команду, чтобы запустить сервер сразу же:

1
2
$ ./vendor/bin/var-dump-server
  [OK] Server listening on tcp://127.0.0.1:9912

Конфигурация сервера сброса с переменными окружения

Если вы предпочитаете не изменять конфигурацию приложения (например, чтобы быстро отладить данный вам проект), используйте переменную окружения VAR_DUMPER_FORMAT.

Сначала, запустите сервер как обычно:

1
$ ./vendor/bin/var-dump-server

Затем, запустите ваш код с переменной окружения VAR_DUMPER_FORMAT=server, сконфигурировав это значение в файле .env вашего приложения . Для консольных команд вы также можете определить эту переменную окружения так:

1
$ VAR_DUMPER_FORMAT=server [your-cli-command]

Note

Хост, использумый форматом server, тот, что сконфигурирован в переменной окружения VAR_DUMPER_SERVER или 127.0.0.1:9912, если он не определён. Если вы хотите, вы также можете сконфигурировать хост в переменной окружения VAR_DUMPER_FORMAT таким образом: VAR_DUMPER_FORMAT=tcp://127.0.0.1:1234.

Интеграция DebugBundle и Twig

DebugBundle позволяет большую интеграцию компонента в приложения Symfony.

Так как генрировние вывода (даже отладки) в контроллере или модели вашего приложения может просто его сломать (например, отправка HTTP заголовков или нарушение вашего просмотра), пакет конфигурирует функцию dump(), чтобы переменные сбрасывались в панели инструментов веб-отладки.

Но если панель инструментов нельзя отобразить так как вы, к примеру, вызвали die()/exit()/dd() или возникла фатальная ошибка, тогда сбросы пишутся в обычном потоке вывода.

В шаблоне Twig доступны две конструкции для сброса переменной. Выбор между двумя в основном зависит от ваших личных предпочтейни, и всё же:

  • {% dump foo.bar %} стоит использовать, когда исходный вывод шаблона не стоит изменять: переменные сбрасываются не встроено, а в панели инструментов веб отладки;
  • и наоборот, {{ dump(foo.bar) }} сбрастывает встроено и поэтому может подходить или не подходить в вашем случае (например, не стоит использовать его в атрибуте HTML или теге <script>).

Это поведение можно изменить, сконфигурировав опцию debug.dump_destination. Прочтите больше об этом и других опциях в справочнике конфигурации DebugBundle.

Tip

Если сброшенное содержание сложное, рассмотрите использование локального окна поиска, чтобы найти конкретные переменные или значения. Для начала, нажмите где угодно в сброшенном содержании, а затем нажмите Ctrl. + F или Cmd. + F, чтобы появилось локальное окно поиска. Поддерживаются все распространённые сокращения для навигации по результатам поиска (Ctrl. + G или Cmd. + G, F3 и т.д.). Когда вы закончите, нажмите Esc., чтобы снова спрятать окно.

Если вы хотите использовать ввод поиска вашего браузера, нажмите Ctrl. + F или Cmd. + F снова, фокусируясь на вводе поиска VarDumper.

Использование компонента VarDumper в вашем наборе тестов PHPUnit

Компонент VarDumper предоставляет черту, который может помочь написать некоторые из ваших тестов для PHPUnit.

Это предоставит вам два новых утверждения:

assertDumpEquals()
верифицирует, чтобы сброс переменной, данный в виде второго аргументы, соответствовал ожидаемому сбросу, предоставленному в качестве первого аргумента.
assertDumpMatchesFormat()
такой же, как и предыдущий метод, но принимает заполнители в ожидаемом сбросе, основанном на методе assertStringMatchesFormat(), предоставленном PHPUnit.

VarDumperTestTrait также содержит такие другие методы:

setUpVarDumper()
используется для конфигурации доступных кастеров и их опций, что является способом только контроля полей, которые вы ожидаете, и позволяет написание кратких тестов.
tearDownVarDumper()
вызывается автоматически после каждого случая, чтобы перезагрузить пользовательскую конфигурацию, сделанную в setUpVarDumper().

Пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;

class ExampleTest extends TestCase
{
    use VarDumperTestTrait;

    protected function setUp(): void
    {
        $casters = [
            \DateTimeInterface::class => static function (\DateTimeInterface $date, array $a, Stub $stub): array {
                $stub->class = 'DateTime';
                return ['date' => $date->format('d/m/Y')];
            },
        ];

        $flags = CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR;

        // это конфигурирует кастеры и флаги для использования во всех тестах этого класса.
        // Если вам нужны пользовательские конфигурации для каждого теста, а не для всего класса,
        // лушче вызовите этот метод setUpVarDumper() из этих тестов.
        $this->setUpVarDumper($casters, $flags);
    }

    public function testWithDumpEquals(): void
    {
        $testedVar = [123, 'foo'];

        // ожидаемое содержание сброса не имеет структуры VarDumper по умолчанию
        // из-за пользовательских кастеров и флагов, использованных в тесте
        $expectedDump = <<<EOTXT
[
  123,
  "foo",
]
EOTXT;

        // если первый аргумент - строка, он должен быть полным ожидаемым сбросом
        $this->assertDumpEquals($expectedDump, $testedVar);

        // если первый аргумент - не строка, assertDumpEquals() сбрасывает его и
        // сравнивает его со сбросом второго аргумента
        $this->assertDumpEquals($testedVar, $testedVar);
    }
}

Примеры сброса и вывод

Для простых переменных, чтение вывода должно быть прямолинейным. Вот некоторые примеры, отображающие первую переменную, определённую в PHP, а потом его представление сброса:

1
2
3
4
5
6
7
8
$var = array(
    'a simple string' => "in an array of 5 elements",
    'a float' => 1.0,
    'an integer' => 1,
    'a boolean' => true,
    'an empty array' => array(),
);
dump($var);
Вывод сброса, показывающий массив с длиной пять и всеми ключами и значениями.

Note

Серая стрелка - это кнопка переключателя для показа / скрытия детей встроенных структур.

1
2
3
4
5
6
7
$var = "Это многострочная строка.\n";
$var .= "Наведение на строку показывает её длину.\n";
$var .= "Длина UTF-8 строк считается в рамках символов UTF-8.\n";
$var .= "Длина не-UTF-8 строк считается октетами.\n";
$var .= "Из-за этого `\xE9` октет (\\xE9),\n";
$var .= "Эта строка не UTF-8 валидна,  поэтому `b` prefix.\n";
dump($var);
Вывод сброса, показывающий строку в нескольких строчках между тремя кавычками.
1
2
3
4
5
6
7
8
9
class PropertyExample
{
    public string $publicProperty = 'The `+` prefix denotes public properties,';
    protected string $protectedProperty = '`#` protected ones and `-` private ones.';
    private string $privateProperty = 'Hovering a property shows a reminder.';
}

$var = new PropertyExample();
dump($var);
Вывод сброса, показывающий объект PropertyExample и все три свойства с их значениями.

Note

`#14` это внутренний объект для обработки. Он позволяет сранвивать два последовательных сброса одного и того же объекта.

1
2
3
4
5
6
7
8
class DynamicPropertyExample
{
    public string $declaredProperty = 'This property is declared in the class definition';
}

$var = new DynamicPropertyExample();
$var->undeclaredProperty = 'Runtime added dynamic properties have `"` around their name.';
dump($var);
Вывод сброса, показывающий объект DynamicPropertyExample и объявленные и необъявленные свойства с их значениями.
1
2
3
4
5
6
7
class ReferenceExample
{
    public string $info = "Цикличные и родственные ссылки отображаются, как `#number`.\n Наведение на них выделяет все экземпляры в одном сбросе.\n";
}
$var = new ReferenceExample();
$var->aCircularReference = $var;
dump($var);
Вывод сброса, показывающий значение свойства "aCircularReference", ссылающегося на родительский объект, вместо повторного показа всех свойств.
1
2
3
4
5
6
7
8
$var = new \ErrorException(
    "Для некоторых объектов свойства имеют специальные значения,\n"
    ."которые лучше всего отображаются в виде ограничений, вроде\n"
    ."`severity` ниже. Наведение на них отображает значение (`2`).\n",
    0,
    E_WARNING
);
dump($var);
Вывод сброса с константой "E_WARNING", показанной в качестве значения "severity".
1
2
3
4
5
6
7
8
$var = array();
$var[0] = 1;
$var[1] =& $var[0];
$var[1] += 1;
$var[2] = array("Hard references (circular or sibling)");
$var[3] =& $var[2];
$var[3][] = "are dumped using `&number` prefixes.";
dump($var);
Вывод сброса, показывающий массивы, на которые ссылаются.
1
2
3
4
5
$var = new \ArrayObject();
$var[] = "Некоторые источники и специальные объекты, как текущий";
$var[] = "иногда лучше всего представить, используя виртуальные";
$var[] = "свойства, описывающие их внутреннее сстояние.";
dump($var);
Вывод сброса ArrayObject.
1
2
3
4
5
6
7
8
$var = new AcmeController(
    "Когда сброс превышает максимальный лимит объектов,\n"
    ."или когда встречаются специальные объекты,\n"
    ."дети могут быть заменены эллипсами и\n"
    ."опционально иметь число, которое сообщает как\n"
    ."и сколько было удалено; В этом случае `9`.\n"
);
dump($var);
Вывод сброса, в котором скрыты дочерние объекты объекта Container.
1
2
3
4
5
6
7
8
9
class Foo
{
    // $foo не инициализирован, что не отличается от null
    private int|float $foo;
    public ?string $baz = null;
}

$var = new Foo();
dump($var);
Вывод сброса, в котором неинициализированное свойство представлено вопросительным знаком, за которым следует определение типа.

Продвинутое использование

Функция dump() является лишь тонкой обёрткой и более удобным способом вызова VarDumper::dump(). Вы можете изменить поведение этой функции, вызвав VarDumper::setHandler($callable). После этого вызовы dump() будут перенаправлены на $callable.

Добавив обработчик, вы можете настроить работу Cloners, Dumpers и Casters, как объясняется ниже. Простая реализация функции-обработчика может выглядеть следующим образом:

1
2
3
4
5
6
7
8
9
10
11
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\VarDumper;

VarDumper::setHandler(function (mixed $var): ?string {
    $cloner = new VarCloner();
    $dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper();

    $dumper->dump($cloner->cloneVar($var));
});

Cloners

Клонер используется для создания промежуточного представления любой переменной PHP. Его выводом является объект Data, который оборачивает это представление.

Вы можете создать объект Data следующим образом:

1
2
3
4
5
6
7
use Symfony\Component\VarDumper\Cloner\VarCloner;

$cloner = new VarCloner();
$data = $cloner->cloneVar($myVar);
// это часто потом передаётся дамперу
// см. пример сверху этой страницы
// $dumper->dump($data);

Какой бы ни была клонированная структура данных, результирующие объекты Data всегда являются сериализуемыми.

При создании представления клонируемый объект накладывает ограничения, так что можно представить только подмножество клонируемой переменной. Перед вызовом :метода:`Symfony\\Component\VarDumper\\Cloner\\VarCloner::cloneVar`, можно настроить такие ограничения:

setMaxItems()
Конфигурирует максимальное количество элементов, которые будут клонироваться за минимальной глубиной вложенности. Подсчёт элементов ведётся по алгоритму "сначала в ширину", так что элементы нижнего уровня имеют более высокий приоритет, чем глубоко вложенные элементы. Указание -1 снимает ограничение.
setMinDepth()
Конфигурирует минимальную глубину дерева, при которой мы гарантированно клонируем все элементы. После достижения этой глубины клонироваться будут только элементы setMaxItems. Значение по умолчанию равно 1, что соответствует старым версиям Symfony.
setMaxString()
Конфигурирует максимальное количество символов, которые будут клонироваться перед обрезанием длинных строк. Указание -1 снимает ограничение.

Перед сбросом вы можете ещё больше ограничить результирующий объект Data, используя следующие методы:

withMaxDepth()
Ограничивает сбросы в диапазоне глубины.
withMaxItemsPerDepth()
Ограничивает количество элементов на уровень глубины.
withRefHandles()
Удаляет обработки внутренних объектов для более компактного вывода (полезно для тестов).
seek()
Выбирает только вложенные подчасти уже клонированных массивов, объектов или ресурсов.

В отличие от предыдущих ограничений клонеров, которые удаляют данные специально, эти ограничения могут быть изменены перед сбросом, так как они не влияют на промежуточное представление внутренне.

Note

Когда ограничений не применяется, объект Data является таким же точным, как и нативная функция serialize и поэтому может быть использован не только для отладки.

Dumpers

Дампер отвечает за вывод строкового представления переменной PHP, используя в качестве ввода Data. Назначение и форматирование этого вывода зависит от дампера.

Данный компонент поставляется с HtmlDumper для вывода HTML и 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));

С помощью первого аргумента конструктора вы можете выбрать поток вывода, в котором будет записываться сброс. По умолчанию CliDumper пишет в php://stdout, а
HtmlDumper - в php://output. Но допустим любой PHP поток (источник или URL).

Вместо адресата потока вы также можете передать ему callable, которое будет вызываться многократно для каждой строки, сгенерированной дампером. Это вызываемое может быть сконфигурировано с помощью первого аргумента конструктора дампера, а также с помощью метода setOutput() или второго аргумента метода dump().

Например, чтобы получить сброс в качестве строки в переменной, вы можете сделать:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 (int $line, int $depth) use (&$output): void {
        // Отрицательная глубина означает "конец сброса"
        if ($depth >= 0) {
            // Добавляет отступ в два пробела к строчке
            $output .= str_repeat('  ', $depth).$line."\n";
        }
    }
);

// $output теперь наполняется представлением сброса $variable

Другой опцией того же самого может быть:

1
2
3
4
5
6
7
8
9
10
11
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 теперь наполняется представлением сброса $variable

Tip

Вы можете передать true во втором аргументе метода dump(), чтобы вернуть сброс в виде строки:

1
$output = $dumper->dump($cloner->cloneVar($variable), true);

Дамеры реализуют интерфейс DataDumperInterface, который указывает метод dump(Data $data). Они также обычно реализуют DumperInterface, который освобождает их от повторной реализации логики, необходимой для прохождения внутренней структуры объекта Data.

HtmlDumper использует тёмную тему по умолчанию. Используйте метод setTheme(), чтобы использовать светлую тему:

1
2
// ...
$htmlDumper->setTheme('light');

HtmlDumper ограничивает длину строки и глубину встаривания вывода, чтобы сделать его более читаемым. Эти опции можно переопределить третьим необязательным параметром метода dump(Data $data):

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\VarDumper\Dumper\HtmlDumper;

$output = fopen('php://memory', 'r+b');

$dumper = new HtmlDumper();
$dumper->dump($var, $output, [
    // 1 и 160 являются значениями по умолчанию для этих опций
    'maxDepth' => 1,
    'maxStringLength' => 160,
]);

Формат вывода дампера может быть точно настроен с помощью двух флажков DUMP_STRING_LENGTH и DUMP_LIGHT_ARRAY, которые передаются в виде битовой карты в третьем аргументе конструктора. Они также могут быть установлены через переменные окружения при использовании assertDumpEquals($dump, $data, $filter, $message) во время модульного тестирования.

Аргумент $filter функции assertDumpEquals() может быть использован для передачи битового поля констант Caster::EXCLUDE_* и влияет на ожидаемый вывод, производимый различными кастерами.

Если DUMP_STRING_LENGTH установлена, то длина строки отображается рядом с ее содержанием:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\AbstractDumper;
use Symfony\Component\VarDumper\Dumper\CliDumper;

$varCloner = new VarCloner();
$var = ['test'];

$dumper = new CliDumper();
echo $dumper->dump($varCloner->cloneVar($var), true);

// array:1 [
//   0 => "test"
// ]

$dumper = new CliDumper(null, null, AbstractDumper::DUMP_STRING_LENGTH);
echo $dumper->dump($varCloner->cloneVar($var), true);

// (added string length before the string)
// array:1 [
//   0 => (4) "test"
// ]

Если DUMP_LIGHT_ARRAY установлен, тогда массивы сбрасываются в сокращённом формате, схожем с краткой нотацией массивов PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\AbstractDumper;
use Symfony\Component\VarDumper\Dumper\CliDumper;

$varCloner = new VarCloner();
$var = ['test'];

$dumper = new CliDumper();
echo $dumper->dump($varCloner->cloneVar($var), true);

// array:1 [
//   0 => "test"
// ]

$dumper = new CliDumper(null, null, AbstractDumper::DUMP_LIGHT_ARRAY);
echo $dumper->dump($varCloner->cloneVar($var), true);

// (no more array:1 prefix)
// [
//   0 => "test"
// ]

Если вы хотите использовать обе опции, то вы можете скомбинировать их, используя логический оператор OR |:

1
2
3
4
5
6
7
8
9
10
11
12
13
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\AbstractDumper;
use Symfony\Component\VarDumper\Dumper\CliDumper;

$varCloner = new VarCloner();
$var = ['test'];

$dumper = new CliDumper(null, null, AbstractDumper::DUMP_STRING_LENGTH | AbstractDumper::DUMP_LIGHT_ARRAY);
echo $dumper->dump($varCloner->cloneVar($var), true);

// [
//   0 => (4) "test"
// ]

Casters

Объекты и источники, вложенные в переменную PHP, "приводятся" к массивам в промежуточном представлении Data. Вы можете настроить представление массива для каждого объекта/источника, подключив к этому процессу Caster. Компонент уже включает в себя множество кастеров для базовых классов PHP и других распространённых классов.

Если вы хотите создать свой собственный кастер, вы можете зарегистрировать его перед клонированием PHP-переменной. Кастеры регистрируются либо в конструкторе клонера, либо с помощью метода addCasters():

use SymfonyComponentVarDumperClonerVarCloner;

$myCasters = [...]; $cloner = new VarCloner($myCasters);

// или

$cloner->addCasters($myCasters);

Предоставленный аргумент $myCasters - это массив, который отображает класс, интерфейс или тип источника к вызываемому:

1
2
3
4
$myCasters = [
    'FooClass' => $myFooClassCallableCaster,
    ':bar resource' => $myBarResourceCallableCaster,
];

Как можно заметить, типы источников снабжаются префиксом : для предотвращения коллизий с именем класса.

Поскольку объект имеет один основной класс и потенциально много родительских классов или интерфейсов, к одному объекту может быть применено множество кастеров. В этом случае кастеры вызываются последовательно, начиная с кастеров, привязанных к интерфейсам, родительским классам и затем к главному классу. Несколько кастеров могут быть зарегистрированы для одного и того же типа источника/класса/интерфейса. Они вызываются в порядке регистрации.

Кастеры отвечают за возврат свойств клонируемого объекта или иисточника в виде массива. Они являются вызываемыми, принимающими пять аргументов:

  • приводимый объект или ресурс;
  • массив, смоделированный для объектов по образцу нативного оператора приведения PHP (array);
  • объект Stub, представляющий основные свойства объекта (класс, тип и т.д.);
  • true/false, когда кастер вызывается вложенным в структуру или нет;
  • битовое поле Caster константы ::EXCLUDE_*.

Вот простой кастер, который ничего не делает:

1
2
3
4
5
6
7
8
use Symfony\Component\VarDumper\Cloner\Stub;

function myCaster(mixed $object, array $array, Stub $stub, bool $isNested, int $filter): array
{
    // ... наполнить/изменить $array в соответствии с вашими нуждами

    return $array;
}

Для объектов параметр $array заполняется с помощью нативного оператора приведения PHP (array) или возвратного значения $object->__debugInfo(), если магический метод существует. Затем возвратное значение одного кастера передается в качестве аргумента массива следующему кастеру в цепочке.

При приведении с помощью оператора (array) PHP добавляет к защищённым свойствам префикс \0*\0, а к приватным - класс, которому принадлежит свойство. Например, \0Foobar\0 будет префиксом для всех приватных свойств объектов типа Foobar. Кастеры следуют этому соглашению и добавляют еще два префикса: \0~\0 для виртуальных свойств и \0+\0 для динамических (добавляемых во время прогона свойств, отсутствующих в объявлении класса).

Note

Хотя вы можете это сделать, рекомендуется не изменять состояние объекта во время приведения его в кастер.

Tip

Перед написанием ваших собственных кастеров, вам стоит рассмотреть уже существующие.

Добавление семантики с метаданными

Поскольку кастеры подключаются к определённым классам или интерфейсам, они знают об объектах, которыми управляют. Изменив объект $stub (третий аргумент любого кастера), можно передать эти знания результирующему объекту Data, а значит, и дамперам. Чтобы помочь вам в этом (как это работает, см. исходный код), компонент поставляется с набором обёрток для распространённой дополнительной семантики. Вы можете использовать:

  • ConstStub, чтобы обернуть значение, которое лучше всего представлять с помощью PHP-константы;
  • ClassStub, чтобы обернуть идентификатор PHP (т.е. имя класса, имя метода, интерфейс и т.д.);
  • CutStub, чтобы заменить большие шумные объекты/строки/и т.д. эллипсами;
  • CutArrayStub, чтобы оставить только некоторые полезные ключи массива;
  • ImgStub, чтобы обернуть изображение;
  • EnumStub, чтобы обернуть набор виртуальных значений (т.е. значений, которые не существуют в виде свойств исходной структуры PHP-данных, но которые стоит упомянуть вместе с настоящими);
  • LinkStub, чтобы обернуть строки, которые могут быть преобразованы в ссылки дамперами;
  • TraceStub и их
  • FrameStub и родственников
  • ArgsStub, чтобы обернуть следы PHP (используемые ExceptionCaster).

Например, если вы знаете, что ваши объекты Product имеют свойство brochure, которое содержит имя файла или URL, вы можете обернуть их в LinkStub, чтобы указать HtmlDumper сделать их кликабельными:

1
2
3
4
5
6
7
8
9
use Symfony\Component\VarDumper\Caster\LinkStub;
use Symfony\Component\VarDumper\Cloner\Stub;

function ProductCaster(Product $object, array $array, Stub $stub, bool $isNested, int $filter = 0): array
{
    $array['brochure'] = new LinkStub($array['brochure']);

    return $array;
}