Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimize hydration performance 4/5
Browse files Browse the repository at this point in the history
PHP Reflection API is known to not be the fastest.
This is OK when only a couple of callls are made but here it is used in a tight loop whereas references to values fetched via Reflection are already available or not even used.

Moving the use as late as possible allows to optimize performance a bit.
tucksaun committed Nov 15, 2022

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
1 parent 0448843 commit c3274c2
Showing 1 changed file with 20 additions and 8 deletions.
28 changes: 20 additions & 8 deletions lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
Original file line number Diff line number Diff line change
@@ -10,15 +10,20 @@
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use ReflectionProperty;

use function array_fill_keys;
use function array_keys;
use function assert;
use function count;
use function is_array;
use function is_object;
use function key;
use function ltrim;
use function spl_object_id;

use const PHP_VERSION_ID;

/**
* The ObjectHydrator constructs an object graph out of an SQL result set.
*
@@ -362,17 +367,16 @@ protected function hydrateRowData(array $row, array &$result)
continue;
}

$parentClass = $this->_metadataCache[$resultSetMapping->aliasMap[$parentAlias]];
$relationField = $resultSetMapping->relationMap[$dqlAlias];
$relation = $parentClass->associationMappings[$relationField];
$reflField = $parentClass->reflFields[$relationField];

// Get a reference to the parent object to which the joined element belongs.
if ($resultSetMapping->isMixed && isset($this->rootAliases[$parentAlias])) {
$objectClass = $resultPointers[$parentAlias];
$parentObject = $objectClass[key($objectClass)];
assert(is_object($parentObject));
} elseif (isset($resultPointers[$parentAlias])) {
$parentObject = $resultPointers[$parentAlias];
assert(is_object($parentObject));
} else {
// Parent object of relation not found, mark as not-fetched again
$element = $this->getEntity($row, $rowData, $dqlAlias);
@@ -386,18 +390,24 @@ protected function hydrateRowData(array $row, array &$result)
continue;
}

$parentClass = $this->_metadataCache[$resultSetMapping->aliasMap[$parentAlias]];
$relation = $parentClass->associationMappings[$relationField];
$reflField = $parentClass->reflFields[$relationField];
assert($reflField instanceof ReflectionProperty);

$oid = spl_object_id($parentObject);

// Check the type of the relation (many or single-valued)
if (! ($relation['type'] & ClassMetadata::TO_ONE)) {
// PATH A: Collection-valued association
$reflFieldValue = $reflField->getValue($parentObject);

if (isset($nonemptyComponents[$dqlAlias])) {
$collKey = $oid . $relationField;
if (isset($this->initializedCollections[$collKey])) {
$reflFieldValue = $this->initializedCollections[$collKey];
} elseif (! isset($this->existingCollections[$collKey])) {
} elseif (isset($this->existingCollections[$collKey])) {
$reflFieldValue = $this->existingCollections[$collKey];
} else {
$reflFieldValue = $this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
}

@@ -437,16 +447,18 @@ protected function hydrateRowData(array $row, array &$result)
// Update result pointer
$resultPointers[$dqlAlias] = $reflFieldValue[$index];
}
} elseif (! $reflFieldValue) {
// phpcs:ignore SlevomatCodingStandard.ControlStructures.AssignmentInCondition.AssignmentInCondition
} elseif (! ($reflFieldValue = $reflField->getValue($parentObject))) {
$this->initRelatedCollection($parentObject, $parentClass, $relationField, $parentAlias);
} elseif ($reflFieldValue instanceof PersistentCollection && $reflFieldValue->isInitialized() === false && ! isset($this->uninitializedCollections[$oid . $relationField])) {
$this->uninitializedCollections[$oid . $relationField] = $reflFieldValue;
}
} else {
// PATH B: Single-valued association
$reflFieldValue = $reflField->getValue($parentObject);

if (! $reflFieldValue || isset($this->_hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && ! $reflFieldValue->__isInitialized())) {
// $reflField->getValue is slow so we first check if the value is isInitialized or not (if possible)
// phpcs:ignore SlevomatCodingStandard.ControlStructures.AssignmentInCondition.AssignmentInCondition
if (isset($this->_hints[Query::HINT_REFRESH]) || (PHP_VERSION_ID >= 70400 && ! $reflField->isInitialized($parentObject)) || ! ($reflFieldValue = $reflField->getValue($parentObject)) || ($reflFieldValue instanceof Proxy && ! $reflFieldValue->__isInitialized())) {
// we only need to take action if this value is null,
// we refresh the entity or its an uninitialized proxy.
if (isset($nonemptyComponents[$dqlAlias])) {

0 comments on commit c3274c2

Please sign in to comment.