Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 73c9cc5

Browse files
committed
[Validator] Optimized performance by calling spl_object_hash() only once per object
1 parent 94ef21e commit 73c9cc5

File tree

1 file changed

+71
-52
lines changed

1 file changed

+71
-52
lines changed

src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ public function validate($value, $constraints = null, $groups = null)
102102

103103
$this->traverseGenericNode(
104104
$value,
105+
is_object($value) ? spl_object_hash($value) : null,
106+
null,
105107
null,
106108
$metadata,
107109
$this->defaultPropertyPath,
@@ -116,23 +118,24 @@ public function validate($value, $constraints = null, $groups = null)
116118

117119
if (is_object($value)) {
118120
$this->cascadeObject(
119-
$value,
120-
$this->defaultPropertyPath,
121-
$groups,
122-
TraversalStrategy::IMPLICIT,
123-
$this->context
121+
$value,
122+
spl_object_hash($value),
123+
$this->defaultPropertyPath,
124+
$groups,
125+
TraversalStrategy::IMPLICIT,
126+
$this->context
124127
);
125128

126129
return $this;
127130
}
128131

129132
if (is_array($value)) {
130133
$this->cascadeCollection(
131-
$value,
132-
$this->defaultPropertyPath,
133-
$groups,
134-
TraversalStrategy::IMPLICIT,
135-
$this->context
134+
$value,
135+
$this->defaultPropertyPath,
136+
$groups,
137+
TraversalStrategy::IMPLICIT,
138+
$this->context
136139
);
137140

138141
return $this;
@@ -148,9 +151,9 @@ public function validate($value, $constraints = null, $groups = null)
148151
/**
149152
* {@inheritdoc}
150153
*/
151-
public function validateProperty($object, $propertyName, $groups = null)
154+
public function validateProperty($container, $propertyName, $groups = null)
152155
{
153-
$classMetadata = $this->metadataFactory->getMetadataFor($object);
156+
$classMetadata = $this->metadataFactory->getMetadataFor($container);
154157

155158
if (!$classMetadata instanceof ClassMetadataInterface) {
156159
// Cannot be UnsupportedMetadataException because of BC with
@@ -165,13 +168,16 @@ public function validateProperty($object, $propertyName, $groups = null)
165168

166169
$propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName);
167170
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups;
171+
$containerHash = spl_object_hash($container);
168172

169173
foreach ($propertyMetadatas as $propertyMetadata) {
170-
$propertyValue = $propertyMetadata->getPropertyValue($object);
174+
$propertyValue = $propertyMetadata->getPropertyValue($container);
171175

172176
$this->traverseGenericNode(
173177
$propertyValue,
174-
$object,
178+
is_object($propertyValue) ? spl_object_hash($propertyValue) : null,
179+
$container,
180+
$containerHash,
175181
$propertyMetadata,
176182
PropertyPath::append($this->defaultPropertyPath, $propertyName),
177183
$groups,
@@ -187,9 +193,9 @@ public function validateProperty($object, $propertyName, $groups = null)
187193
/**
188194
* {@inheritdoc}
189195
*/
190-
public function validatePropertyValue($object, $propertyName, $value, $groups = null)
196+
public function validatePropertyValue($container, $propertyName, $value, $groups = null)
191197
{
192-
$classMetadata = $this->metadataFactory->getMetadataFor($object);
198+
$classMetadata = $this->metadataFactory->getMetadataFor($container);
193199

194200
if (!$classMetadata instanceof ClassMetadataInterface) {
195201
// Cannot be UnsupportedMetadataException because of BC with
@@ -204,11 +210,14 @@ public function validatePropertyValue($object, $propertyName, $value, $groups =
204210

205211
$propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName);
206212
$groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups;
213+
$containerHash = spl_object_hash($container);
207214

208215
foreach ($propertyMetadatas as $propertyMetadata) {
209216
$this->traverseGenericNode(
210217
$value,
211-
$object,
218+
is_object($value) ? spl_object_hash($value) : null,
219+
$container,
220+
$containerHash,
212221
$propertyMetadata,
213222
PropertyPath::append($this->defaultPropertyPath, $propertyName),
214223
$groups,
@@ -266,12 +275,12 @@ protected function normalizeGroups($groups)
266275
* @see CollectionNode
267276
* @see TraversalStrategy
268277
*/
269-
private function traverseClassNode($value, ClassMetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context)
278+
private function traverseClassNode($value, $valueHash, ClassMetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context)
270279
{
271280
// Replace "Default" group by group sequence, if appropriate
272281
$groups = $this->replaceDefaultGroup($value, $metadata, $groups);
273282

274-
$groups = $this->validateNode($value, $value, $metadata, $propertyPath, $groups, $traversalStrategy, $context);
283+
$groups = $this->validateNode($value, $valueHash, null, null, $metadata, $propertyPath, $groups, $traversalStrategy, $context);
275284

276285
if (0 === count($groups)) {
277286
return;
@@ -288,9 +297,13 @@ private function traverseClassNode($value, ClassMetadataInterface $metadata = nu
288297
));
289298
}
290299

300+
$propertyValue = $propertyMetadata->getPropertyValue($value);
301+
291302
$this->traverseGenericNode(
292-
$propertyMetadata->getPropertyValue($value),
303+
$propertyValue,
304+
is_object($propertyValue) ? spl_object_hash($propertyValue) : null,
293305
$value,
306+
$valueHash,
294307
$propertyMetadata,
295308
$propertyPath
296309
? $propertyPath.'.'.$propertyName
@@ -392,6 +405,7 @@ private function cascadeCollection($collection, $propertyPath, array $groups, $t
392405
if (is_object($value)) {
393406
$this->cascadeObject(
394407
$value,
408+
spl_object_hash($value),
395409
$propertyPath.'['.$key.']',
396410
$groups,
397411
$traversalStrategy,
@@ -418,9 +432,9 @@ private function cascadeCollection($collection, $propertyPath, array $groups, $t
418432
* @param Node $node The node
419433
* @param ExecutionContextInterface $context The current execution context
420434
*/
421-
private function traverseGenericNode($value, $object, MetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context)
435+
private function traverseGenericNode($value, $valueHash, $container, $containerHash, MetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups, $traversalStrategy, ExecutionContextInterface $context)
422436
{
423-
$groups = $this->validateNode($value, $object, $metadata, $propertyPath, $groups, $traversalStrategy, $context);
437+
$groups = $this->validateNode($value, $valueHash, $container, $containerHash, $metadata, $propertyPath, $groups, $traversalStrategy, $context);
424438

425439
if (0 === count($groups)) {
426440
return;
@@ -467,6 +481,7 @@ private function traverseGenericNode($value, $object, MetadataInterface $metadat
467481
// (BC with Symfony < 2.5)
468482
$this->cascadeObject(
469483
$value,
484+
$valueHash,
470485
$propertyPath,
471486
$cascadedGroups,
472487
$traversalStrategy,
@@ -492,7 +507,7 @@ private function traverseGenericNode($value, $object, MetadataInterface $metadat
492507
* traversal of the object, a new collection node is put on the stack.
493508
* Otherwise, an exception is thrown.
494509
*
495-
* @param object $object The object to cascade
510+
* @param object $container The object to cascade
496511
* @param string $propertyPath The current property path
497512
* @param string[] $groups The validated groups
498513
* @param integer $traversalStrategy The strategy for traversing the
@@ -507,10 +522,10 @@ private function traverseGenericNode($value, $object, MetadataInterface $metadat
507522
* metadata factory does not implement
508523
* {@link ClassMetadataInterface}
509524
*/
510-
private function cascadeObject($object, $propertyPath, array $groups, $traversalStrategy, ExecutionContextInterface $context)
525+
private function cascadeObject($container, $containerHash, $propertyPath, array $groups, $traversalStrategy, ExecutionContextInterface $context)
511526
{
512527
try {
513-
$classMetadata = $this->metadataFactory->getMetadataFor($object);
528+
$classMetadata = $this->metadataFactory->getMetadataFor($container);
514529

515530
if (!$classMetadata instanceof ClassMetadataInterface) {
516531
throw new UnsupportedMetadataException(sprintf(
@@ -522,7 +537,8 @@ private function cascadeObject($object, $propertyPath, array $groups, $traversal
522537
}
523538

524539
$this->traverseClassNode(
525-
$object,
540+
$container,
541+
$containerHash,
526542
$classMetadata,
527543
$propertyPath,
528544
$groups,
@@ -532,7 +548,7 @@ private function cascadeObject($object, $propertyPath, array $groups, $traversal
532548
);
533549
} catch (NoSuchMetadataException $e) {
534550
// Rethrow if not Traversable
535-
if (!$object instanceof \Traversable) {
551+
if (!$container instanceof \Traversable) {
536552
throw $e;
537553
}
538554

@@ -542,7 +558,7 @@ private function cascadeObject($object, $propertyPath, array $groups, $traversal
542558
}
543559

544560
$this->cascadeCollection(
545-
$object,
561+
$container,
546562
$propertyPath,
547563
$groups,
548564
$traversalStrategy,
@@ -563,14 +579,12 @@ private function cascadeObject($object, $propertyPath, array $groups, $traversal
563579
*
564580
* @return array The groups in which the successor nodes should be validated
565581
*/
566-
public function validateNode($value, $object, MetadataInterface $metadata = null, $propertyPath, array $groups, $traversalStrategy, ExecutionContextInterface $context)
582+
public function validateNode($value, $valueHash, $container, $containerHash, MetadataInterface $metadata = null, $propertyPath, array $groups, $traversalStrategy, ExecutionContextInterface $context)
567583
{
568584
$context->setValue($value);
569585
$context->setMetadata($metadata);
570586
$context->setPropertyPath($propertyPath);
571587

572-
$objectHash = is_object($object) ? spl_object_hash($object) : null;
573-
574588
// if group (=[<G1,G2>,G3,G4]) contains group sequence (=<G1,G2>)
575589
// then call traverse() with each entry of the group sequence and abort
576590
// if necessary (G1, G2)
@@ -587,20 +601,20 @@ public function validateNode($value, $object, MetadataInterface $metadata = null
587601
// Use the object hash for group sequences
588602
$groupHash = is_object($group) ? spl_object_hash($group) : $group;
589603

590-
if ($context->isObjectValidatedForGroup($objectHash, $groupHash)) {
604+
if ($context->isObjectValidatedForGroup($valueHash, $groupHash)) {
591605
// Skip this group when validating the successor nodes
592606
// (property and/or collection nodes)
593607
unset($groups[$key]);
594608

595609
continue;
596610
}
597611

598-
$context->markObjectAsValidatedForGroup($objectHash, $groupHash);
612+
$context->markObjectAsValidatedForGroup($valueHash, $groupHash);
599613
}
600614

601615
if ($group instanceof GroupSequence) {
602616
// Traverse group sequence until a violation is generated
603-
$this->stepThroughGroupSequence($value, $object, $metadata, $propertyPath, $traversalStrategy, $group, $context);
617+
$this->stepThroughGroupSequence($value, $valueHash, $container, $containerHash, $metadata, $propertyPath, $traversalStrategy, $group, $context);
604618

605619
// Skip the group sequence when validating successor nodes
606620
unset($groups[$key]);
@@ -609,7 +623,7 @@ public function validateNode($value, $object, MetadataInterface $metadata = null
609623
}
610624

611625
// Validate normal group
612-
$this->validateNodeForGroup($value, $objectHash, $metadata, $group, $context);
626+
$this->validateNodeForGroup($value, $valueHash, $containerHash, $metadata, $group, $context);
613627
}
614628

615629
return $groups;
@@ -625,7 +639,7 @@ public function validateNode($value, $object, MetadataInterface $metadata = null
625639
* @param GroupSequence $groupSequence The group sequence
626640
* @param ExecutionContextInterface $context The execution context
627641
*/
628-
private function stepThroughGroupSequence($value, $object, MetadataInterface $metadata = null, $propertyPath, $traversalStrategy, GroupSequence $groupSequence, ExecutionContextInterface $context)
642+
private function stepThroughGroupSequence($value, $valueHash, $container, $containerHash, MetadataInterface $metadata = null, $propertyPath, $traversalStrategy, GroupSequence $groupSequence, ExecutionContextInterface $context)
629643
{
630644
$violationCount = count($context->getViolations());
631645

@@ -640,6 +654,7 @@ private function stepThroughGroupSequence($value, $object, MetadataInterface $me
640654
if ($metadata instanceof ClassMetadataInterface) {
641655
$this->traverseClassNode(
642656
$value,
657+
$valueHash,
643658
$metadata,
644659
$propertyPath,
645660
$groups,
@@ -650,7 +665,9 @@ private function stepThroughGroupSequence($value, $object, MetadataInterface $me
650665
} else {
651666
$this->traverseGenericNode(
652667
$value,
653-
$object,
668+
$valueHash,
669+
$container,
670+
$containerHash,
654671
$metadata,
655672
$propertyPath,
656673
$groups,
@@ -673,36 +690,38 @@ private function stepThroughGroupSequence($value, $object, MetadataInterface $me
673690
* @param Node $node The validated node
674691
* @param string $group The group to validate
675692
* @param ExecutionContextInterface $context The execution context
676-
* @param string $objectHash The hash of the node's
693+
* @param string $containerHash The hash of the node's
677694
* object (if any)
678695
*
679696
* @throws \Exception
680697
*/
681-
private function validateNodeForGroup($value, $objectHash, MetadataInterface $metadata = null, $group, ExecutionContextInterface $context)
698+
private function validateNodeForGroup($value, $valueHash, $containerHash, MetadataInterface $metadata = null, $group, ExecutionContextInterface $context)
682699
{
683700
$context->setGroup($group);
684701

702+
$propertyName = $metadata instanceof PropertyMetadataInterface
703+
? $metadata->getPropertyName()
704+
: null;
705+
685706
foreach ($metadata->findConstraints($group) as $constraint) {
686707
// Prevent duplicate validation of constraints, in the case
687708
// that constraints belong to multiple validated groups
688-
if (null !== $objectHash) {
709+
if (null !== $propertyName) {
689710
$constraintHash = spl_object_hash($constraint);
690711

691-
if ($metadata instanceof ClassMetadataInterface) {
692-
if ($context->isClassConstraintValidated($objectHash, $constraintHash)) {
693-
continue;
694-
}
695-
696-
$context->markClassConstraintAsValidated($objectHash, $constraintHash);
697-
} elseif ($metadata instanceof PropertyMetadataInterface) {
698-
$propertyName = $metadata->getPropertyName();
712+
if ($context->isPropertyConstraintValidated($containerHash, $propertyName, $constraintHash)) {
713+
continue;
714+
}
699715

700-
if ($context->isPropertyConstraintValidated($objectHash, $propertyName, $constraintHash)) {
701-
continue;
702-
}
716+
$context->markPropertyConstraintAsValidated($containerHash, $propertyName, $constraintHash);
717+
} elseif (null !== $valueHash) {
718+
$constraintHash = spl_object_hash($constraint);
703719

704-
$context->markPropertyConstraintAsValidated($objectHash, $propertyName, $constraintHash);
720+
if ($context->isClassConstraintValidated($valueHash, $constraintHash)) {
721+
continue;
705722
}
723+
724+
$context->markClassConstraintAsValidated($valueHash, $constraintHash);
706725
}
707726

708727
$validator = $this->validatorFactory->getInstance($constraint);

0 commit comments

Comments
 (0)