为什么 Doctrine\ORM\Configuration 的 "DoctrineProxies" 对象包含宇宙?
Why does Doctrine\ORM\Configuration's "DoctrineProxies" Object contain the Universe?
在我的 ORM 代码中,我有一个实体,其字段被罚款如下:
//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
)
请注意 print_r()
函数上面有 6(六)行。
一切都很好,直到
接下来,我将 $productId
列更改为 ManyToOne
我的 Item
实体 class 的关系,如下所示:
/**
* @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
打印的行
问题:
这个对象到底是什么,为什么打印出来的时候大到占用了将近300Mb的磁盘space?
我不禁想知道这种复杂性是否容易在日常代码中引起性能问题。例如,我不会在我的日常代码中打印出 $instance
变量的内容,但我肯定会 return 来自方法调用的庞大内容。这是否意味着它是从上面的 $em->find(Item::class, 2);
调用传递的 300Mb 变量?
(非常)部分上市
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]
DoctrineProxies\__CG__\Application\Entity\Product
是代理 class... 这意味着学说实际上不会从数据库中获取实体(为了性能)除非需要(即调用 $product->getName()
那些代理 类 在彼此之间的递归循环,并且如您所见非常大...除非您深入研究,否则您并不真正需要那里的大部分信息...您永远不应该使用 print_r
...在新的 symfony 中2.7+ 我认为在调试模式下有一个名为 dump()
的函数......如果你使用它来打印它具有循环保护的实体并且它只显示参考编号......你也可以使用 \Doctrine\Common\Util\Debug::dump()
也将打印出比 2^234234234 行更小的列表 ...
如果没有 XDebug 或类似工具(限制转储对象的大小),您无法转储代理对象。
问题真的非常简单:
代理 -> 引用 EntityManager -> 引用 UnitOfWork -> 包含代理
这显然会导致递归数据结构转储,这反过来又会在您尝试无合理限制地转储它时导致混乱。
在我的 ORM 代码中,我有一个实体,其字段被罚款如下:
//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
)
请注意 print_r()
函数上面有 6(六)行。
一切都很好,直到
接下来,我将 $productId
列更改为 ManyToOne
我的 Item
实体 class 的关系,如下所示:
/**
* @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
问题:
这个对象到底是什么,为什么打印出来的时候大到占用了将近300Mb的磁盘space?
我不禁想知道这种复杂性是否容易在日常代码中引起性能问题。例如,我不会在我的日常代码中打印出 $instance
变量的内容,但我肯定会 return 来自方法调用的庞大内容。这是否意味着它是从上面的 $em->find(Item::class, 2);
调用传递的 300Mb 变量?
(非常)部分上市
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]
DoctrineProxies\__CG__\Application\Entity\Product
是代理 class... 这意味着学说实际上不会从数据库中获取实体(为了性能)除非需要(即调用 $product->getName()
那些代理 类 在彼此之间的递归循环,并且如您所见非常大...除非您深入研究,否则您并不真正需要那里的大部分信息...您永远不应该使用 print_r
...在新的 symfony 中2.7+ 我认为在调试模式下有一个名为 dump()
的函数......如果你使用它来打印它具有循环保护的实体并且它只显示参考编号......你也可以使用 \Doctrine\Common\Util\Debug::dump()
也将打印出比 2^234234234 行更小的列表 ...
如果没有 XDebug 或类似工具(限制转储对象的大小),您无法转储代理对象。
问题真的非常简单:
代理 -> 引用 EntityManager -> 引用 UnitOfWork -> 包含代理
这显然会导致递归数据结构转储,这反过来又会在您尝试无合理限制地转储它时导致混乱。