オブジェクトを操作する能力を失わずに高速化したい場合はObjectHydrator
、独自のカスタム ハイドレーターを作成する必要があります。
そのためには、次の手順を実行する必要があります。
Hydrator
を拡張する独自のクラスを作成しますDoctrine\ORM\Internal\Hydration\AbstractHydrator
。私の場合、ArrayHydrator
エイリアスをオブジェクト変数にマッピングする手間を省くために拡張しています。
use Doctrine\ORM\Internal\Hydration\ArrayHydrator;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use PDO;
class Hydrator extends ArrayHydrator
{
const HYDRATE_SIMPLE_OBJECT = 55;
protected function hydrateAllData()
{
$entityClassName = reset($this->_rsm->aliasMap);
$entity = new $entityClassName();
$entities = [];
foreach (parent::hydrateAllData() as $data) {
$entities[] = $this->hydrateEntity(clone $entity, $data);
}
return $entities;
}
protected function hydrateEntity(AbstractEntity $entity, array $data)
{
$classMetaData = $this->getClassMetadata(get_class($entity));
foreach ($data as $fieldName => $value) {
if ($classMetaData->hasAssociation($fieldName)) {
$associationData = $classMetaData->getAssociationMapping($fieldName);
switch ($associationData['type']) {
case ClassMetadataInfo::ONE_TO_ONE:
case ClassMetadataInfo::MANY_TO_ONE:
$data[$fieldName] = $this->hydrateEntity(new $associationData['targetEntity'](), $value);
break;
case ClassMetadataInfo::MANY_TO_MANY:
case ClassMetadataInfo::ONE_TO_MANY:
$entities = [];
$targetEntity = new $associationData['targetEntity']();
foreach ($value as $associatedEntityData) {
$entities[] = $this->hydrateEntity(clone $targetEntity, $associatedEntityData);
}
$data[$fieldName] = $entities;
break;
default:
throw new \RuntimeException('Unsupported association type');
}
}
}
$entity->populate($data);
return $entity;
}
}
Doctrine 構成でハイドレーターを登録します。
$config = new \Doctrine\ORM\Configuration()
$config->addCustomHydrationMode(Hydrator::HYDRATE_SIMPLE_OBJECT, Hydrator::class);
AbstractEntity
エンティティを移入するメソッドを使用して作成します。私のサンプルでは、エンティティに既に作成されているセッター メソッドを使用して、エンティティにデータを入力しています。
abstract class AbstractEntity
{
public function populate(Array $data)
{
foreach ($data as $field => $value) {
$setter = 'set' . ucfirst($field);
if (method_exists($this, $setter)) {
$this->{$setter}($value);
}
}
}
}
これらの 3 つの手順の後、クエリ メソッドHYDRATE_SIMPLE_OBJECT
の代わりに渡すことができます。この実装は十分にテストされていませんが、より高度な機能のためにネストされたマッピングでも機能するはずであり、接続を実装しない限り、エンティティを簡単に保存/更新する機能が失われることに注意してください。オブジェクトは単なる単純なオブジェクトであるため、シリアライズしてキャッシュすることができます。HYDRATE_OBJECT
getResult
Hydrator::hydrateAllData()
EntityManager
性能テスト
テストコード:
$hydrators = [
'HYDRATE_OBJECT' => \Doctrine\ORM\AbstractQuery::HYDRATE_OBJECT,
'HYDRATE_ARRAY' => \Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY,
'HYDRATE_SIMPLE_OBJECT' => Hydrator::HYDRATE_SIMPLE_OBJECT,
];
$queryBuilder = $repository->createQueryBuilder('u');
foreach ($hydrators as $name => $hydrator) {
$start = microtime(true);
$queryBuilder->getQuery()->getResult($hydrator);
$end = microtime(true);
printf('%s => %s <br/>', $name, $end - $start);
}
それぞれ 20~ 列の 940 レコードに基づく結果:
HYDRATE_OBJECT => 0.57511210441589
HYDRATE_ARRAY => 0.19534111022949
HYDRATE_SIMPLE_OBJECT => 0.37919402122498