Компонент VarExporter

Дата обновления перевода 2022-01-03

Компонент VarExporter

Компонент VarExporter экспортирует всю структуру PHP-данных, поддающуюся сериализации, в чистый PHP-код и позволяет инстанциировать и населять объекты без вызова к их конструкторам.

Установка

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

Note

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

Экспорт/сериализация переменных

Главная функция этого компонента - сериализовать структуры PHP-данных в чистый PHP-код, схоже в функцией PHP var_export:

1
2
3
4
5
6
7
8
use Symfony\Component\VarExporter\VarExporter;

$exported = VarExporter::export($someVariable);
// сохраните $exported данные в каком-то файле или системе кеширования для дальнейшего повторного использования
$data = file_put_contents('exported.php', $exported);

// позже, регенерируйте изначальную переменную, когда она вам понадобится
$regeneratedVariable = require 'exported.php';

Причина использования этого компонента вместо serialize() или igbinary кроется в производительности: благодаря OPcache, итоговый код значительно быстрее и более эффективный с точки зрения памяти, чем при использовании unserialize() или igbinary_unserialize().

Кроме этого, есть некоторые небольшие различия:

  • Если изначальная переменная это определяет, вся семантика, ассоциированная с serialize() (такая как __wakeup(), __sleep(), и Serializable) сохраняется (var_export() игнорирует это);
  • Ссылки, задействующие экземпляры SplObjectStorage, ArrayObject или ArrayIterator сохраняются;
  • Отсутствующие классы вызывают ClassNotFoundException вместо десериализации в объекты PHP_Incomplete_Class;
  • Классы Reflection*, IteratorIterator и RecursiveIteratorIterator вызывают исключение при попытке сериализации.

Экспортированный данные - это PSR-2, совместимый с PHP-файлом. Рассмотрите, к примеру, следующую иерархию классов:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
abstract class AbstractClass
{
    protected $foo;
    private $bar;

    protected function setBar($bar)
    {
        $this->bar = $bar;
    }
}

class ConcreteClass extends AbstractClass
{
    public function __construct()
    {
        $this->foo = 123;
        $this->setBar(234);
    }
}

При экспорте данных ConcreteClass с помощью VarExporter, сгенерированный PHP-файл выглядит так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate(
    $o = [
        clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\ConcreteClass'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\ConcreteClass')),
    ],
    null,
    [
        'Symfony\\Component\\VarExporter\\Tests\\AbstractClass' => [
            'foo' => [
                123,
            ],
            'bar' => [
                234,
            ],
        ],
    ],
    $o[0],
    []
);

Инстанциация PHP-классов

Другой основной функцией, предоставленной этим компонентом, является формирователь, который может создавать объекты и устанавливать их свойства без вызова их конструкторов или любых других методов:

1
2
3
4
5
6
7
8
9
10
11
12
use Symfony\Component\VarExporter\Instantiator;

// создает пустой экземпляр Foo
$fooObject = Instantiator::instantiate(Foo::class);

// создает экземпляр Foo и устанавливает одно из его свойств
$fooObject = Instantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]);

// создает экземпляр Foo и устанавливает частное свойство, определенное в его родительском классе Bar
$fooObject = Instantiator::instantiate(Foo::class, [], [
    Bar::class => ['privateBarProperty' => $propertyValue],
]);

Экземпляры ArrayObject, ArrayIterator и SplObjectHash могут быть созданы используя специальное имя свойства "\0" для определения их внутреннего значения:

1
2
3
4
5
6
7
8
9
// Создает SplObjectHash, где $info1 ассоциируется с $object1, и т.д.
$theObject = Instantiator::instantiate(SplObjectStorage::class, [
    "\0" => [$object1, $info1, $object2, $info2...],
]);

// создает ArrayObject, населенный $inputArray
$theObject = Instantiator::instantiate(ArrayObject::class, [
    "\0" => [$inputArray],
]);