Просунуте використання компонента VarDumper

Дата оновлення перекладу 2022-11-17

Просунуте використання компонента VarDumper

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

Додавши обробник, ви можете налаштувати Cloner, Dumper і Caster, як пояснюється нижче. Проста реалізація функції обробника може виглядати таким чином:

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

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

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

Cloner

Клонувальник використовується для створення середнього представлення будь-якої змінної 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 завжди піддаються серіалізації.

Клонувальник застосовує обмеження при створенні представлення, так що один може представляти лише піднабір клонованої змінної. До виклику вызова cloneVar(), ви можете сконфігурувати ці обмеження:

setMaxItems()
Конфігурує максимальну кількість обʼєктів, які будуть клонованні після мінімальної глибини вкладення. Обʼєкти рахуються з використанням алгоритму за рівнями, так що обʼєкти нижнього рівня матимуть вищий пріоритет, ніж глибоко вкладені обʼєкти; Вказавши -1, ви видалите обмеження.
setMinDepth()
Конфігурує мінімальну глибину дерева, де ми гарантовано клонуємо всі обʼєкти. Після того як досягнута ця глибина, тільки обʼєкти setMaxItems будуть клоновані. Значення за замовчуванням - 1, що не вступає у конфлікт зі старішими версіями Symfony.
setMaxString()
Конфігурує максимальну кількість символів, яка буде клонована перед обрізанням занадто довгих рядків. Вказавши -1, ви видалите обмеження.

До скидання ви можете ще більше обмежити результуючий обʼєкт Data, використовуючи наступні методи:

withMaxDepth()
Обмежує скидання у вимірі глибини.
withMaxItemsPerDepth()
Обмежує кількість обʼєктів на рівень глибини.
withRefHandles()
Видалає обробки внутрішніх обʼєктів для більш просторого виведення (корисно для текстів).
seek()
Обирає лише підчастини вже клонованих масивів, обʼєктів або джерел.

На відміну від попередніх обмежень у клонувальниках, які спеціально видаляють дані, ці можуть змінюватися до скидання, так як вони не впливають на проміжкове представлення внутрішньо.

Note

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

Dumper

Двммпер відповідає за виведеня представлення рядку змінної 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 ($line, $depth) use (&$output) {
        // Відʼємна глибина означає "кінець скидання"
        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, array(
    // 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);

// (додана довжина рядку перед рядком)
// 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"
// ]

Caster

Обʼєкти та джерела, вкладені в PHP-змінну "призводяться" до масивів у проміжковому представленні Data. Ви можете налаштувати представлення масиву для кожного обʼєкта/джерела, підключивши кастер до цього процесу. Компонент вже включає в себе кастер для базових PHP-класів та інших загальних класів.

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

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

$myCasters = array(...);
$cloner = new VarCloner($myCasters);

// або

$cloner->addCasters($myCasters);

Наданий аргумент $myCasters є масивом, що зʼєднує клас, інтерфейс або тип джерела з викликаним:

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

Як ви можете помітити, типи джерел мають префікси :, щоб уникнути колізій з іменами класів.

Так як обʼєкт має один основний клас та потенційну множину батьківських класів або інтерфейсів, багато кастерів можуть бути застосовані до одного обʼєкта. У такому випадку, кастери викликаються один за одним, починаючи з кастерів, привʼязаних до інтерфейсів, батьківських классів, а потім до основного класу. Декілька кастерів також можуть бути зареєстровані для одного типу/класу/інтерфейсу джерела. Вони називаються порядком реєстрації.

Кастери відповідають за повернення властивостей обʼєкта або джерела, які клонуються у масив. Вони є викликаними, що приймають 5 аргументів:

  • обʼєкт або джерело, що призводиться;
  • масив, змодельований для обʼєктів піся нативного оператора-призведення PHP (array);
  • обʼєкт Stub, що представляє головні властивості обʼєкта (клас, тип і т.д.);
  • true/false, коли викликається вкладений або не вкладений у структуру кастер;
  • Трохи констант поля Caster ::EXCLUDE_*.

Ось простий кастер, який нічого не робить:

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

function myCaster($object, $array, Stub $stub, $isNested, $filter)
{
    // ... наповнити/змінити $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, Stub $stub, $isNested, $filter = 0)
{
    $array['brochure'] = new LinkStub($array['brochure']);

    return $array;
}