В моем коде ORM у меня есть Entity с полем, оштрафованным следующим образом:

//part of entity class Item:
/** @Column(name="product_id", type="integer") */
private $productId;

Затем я выполнил этот код:

//3 lines ~straight out of Doctrine configuration to get EntityManager
include 'config/doctrine-config.php';
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
$em = EntityManager::create($dbParams, $config);

//my own code to retrieve an entity instance:
$instance = $em->find(Item::class, 2);
print_r($instance);

И вот результат, который я получаю (пропуская несколько других похожих свойств):

Application\Entity\Item Object
(
    [id:Application\Entity\Item:private] => 2
    [description:Application\Entity\Item:private] => Product Kit
    [productId:Application\Entity\Item:private] => -1
)

Обратите внимание на 6 (шесть) строк выше, которые вышли из функции print_r().

И все было хорошо, пока

Затем я изменил столбец $productId на ManyToOne Relationship в моем классе Item Entity, например:

/** 
 * @ManyToOne(targetEntity="Product", inversedBy="id")
 * @JoinColumn(name="product_id", referencedColumnName="id")
 */
private $productId;

Я запустил тот же код.

ВЫШЛА ВСЕЛЕННАЯ ИЗ 2 392 600 ЛИНИЙ, ЧТО?

Два миллиона триста девяносто две тысячи шестьсот строк строк вывода print_r.

Глядя на распечатку, я вижу, что DoctrineProxies\__CG__\Application\Entity\Product Объект содержит 2,392,564 строк, напечатанных print_r

Вопрос:

Что именно находится в этом объекте и почему он такой большой, что при распечатке занимает почти 300 МБ дискового пространства?

Я не могу не задаться вопросом, может ли такая сложность вызывать проблемы с производительностью в повседневном коде. Например, я не распечатываю содержимое переменной $instance в своем повседневном коде, но я обязательно возвращаю громадность вызова метода. Означает ли это, что это 300-мегабайтная переменная, которая передается из вызова $em->find(Item::class, 2); выше?

(Очень) частичное объявление

Application\Entity\Item Object
(
 [id:Application\Entity\Item:private] => 2
 [description:Application\Entity\Item:private] => Product Kit
 [ProductId:Application\Entity\Item:private] => DoctrineProxies\__CG__\Application\Entity\Product Object
  (
   [__initializer__] => Closure Object
    (
     [static] => Array
      (
       [entityPersister] => Doctrine\ORM\Persisters\Entity\BasicEntityPersister Object
        (
         [class:protected] => Doctrine\ORM\Mapping\ClassMetadata Object
          (
           [name] => Application\Entity\Product
           [namespace] => Application\Entity
           [rootEntityName] => Application\Entity\Product
           [inheritanceType] => 1
           [generatorType] => 5
           [fieldMappings] => Array
            (
             [id] => Array
              (
               [fieldName] => id
               [type] => integer
               [scale] => 0
               [length] => 
               [unique] => 
               [nullable] => 
               [precision] => 0
               [columnName] => id
               [id] => 1
              )
           [fieldNames] => Array
            (
             [id] => id
             [description] => description
            )

       [columnNames] => Array
            (
             [id] => id
             [description] => description
            )

       [idGenerator] => Doctrine\ORM\Id\AssignedGenerator Object
           [reflClass] => ReflectionClass Object
            (
             [name] => Application\Entity\Product
            )

       [namingStrategy:protected] => Doctrine\ORM\Mapping\DefaultNamingStrategy Object
           [instantiator:Doctrine\ORM\Mapping\ClassMetadataInfo:private] => Doctrine\Instantiator\Instantiator Object

          )

     [conn:protected] => Doctrine\DBAL\Connection Object
          (
           [_conn:protected] => Doctrine\DBAL\Driver\PDOConnection Object
            (
            )

       [_config:protected] => Doctrine\ORM\Configuration Object
            (
             [_attributes:protected] => Array
              (
               [metadataCacheImpl] => Doctrine\Common\Cache\ArrayCache Object
                (
                 [data:Doctrine\Common\Cache\ArrayCache:private] => Array
                  (
                   [dc2_b1e855bc8c5c80316087e39e6c34bc26_[Application\Entity\Item$CLASSMETADATA][1]] => Array
                    (
                     [0] => Doctrine\ORM\Mapping\ClassMetadata Object
                      (
                       [name] => Application\Entity\Item
                       [namespace] => Application\Entity
                       [rootEntityName] => Application\Entity\Item
                       [customGeneratorDefinition] => 
                       [customRepositoryClassName] => 
                       [isMappedSuperclass] => 
                       [isEmbeddedClass] => 
                       [parentClasses] => Array

    [BAZILLION LINES redacted for brevity]
0
Dennis 6 Май 2016 в 18:57

2 ответа

Лучший ответ

Вы не можете выгрузить прокси-объект без XDebug или аналогичных инструментов (которые ограничивают размер выгружаемого объекта).

Проблема действительно очень проста:

Прокси -> ссылки EntityManager -> ссылки UnitOfWork -> содержит прокси

Это, очевидно, приводит к рекурсивному дампу структуры данных, что, в свою очередь, приводит к беспорядку всякий раз, когда вы пытаетесь сбросить его без разумных ограничений.

3
Ocramius 6 Май 2016 в 16:18

DoctrineProxies\__CG__\Application\Entity\Product является прокси-классом ... что означает, что доктрина фактически не извлекает объект из базы данных (для производительности), если он не нужен (т.е. вызов $product->getName(), эти прокси-классы находятся в рекурсивном цикле друг с другом и ОЧЕНЬ большой, как вы видели ... большая часть информации там вам действительно не нужна, если вы не ныряете глубоко ... вам никогда не следует использовать print_r ... в новой версии Symfony 2.7+, я думаю, есть функция называется dump() в режиме отладки ... если вы используете это для печати объекта, у него есть защита от петель, и он просто показывает ссылочные номера ... вы также можете использовать \Doctrine\Common\Util\Debug::dump(), который также распечатает меньший список, чем 2 ^ 234234234 строк ...

1
Drmjo 6 Май 2016 в 16:10