@@ -76,19 +76,14 @@ class PropertyAccessor implements PropertyAccessorInterface
7676 * Should not be used by application code. Use
7777 * {@link PropertyAccess::createPropertyAccessor()} instead.
7878 */
79- public function __construct (bool $ magicCall = false , bool $ throwExceptionOnInvalidIndex = false , CacheItemPoolInterface $ cacheItemPool = null , bool $ throwExceptionOnInvalidPropertyPath = true )
79+ public function __construct (bool $ magicCall = false , bool $ throwExceptionOnInvalidIndex = false , CacheItemPoolInterface $ cacheItemPool = null , bool $ throwExceptionOnInvalidPropertyPath = true , PropertyReadInfoExtractorInterface $ readInfoExtractor = null , PropertyWriteInfoExtractorInterface $ writeInfoExtractor = null )
8080 {
8181 $ this ->magicCall = $ magicCall ;
8282 $ this ->ignoreInvalidIndices = !$ throwExceptionOnInvalidIndex ;
8383 $ this ->cacheItemPool = $ cacheItemPool instanceof NullAdapter ? null : $ cacheItemPool ; // Replace the NullAdapter by the null value
8484 $ this ->ignoreInvalidProperty = !$ throwExceptionOnInvalidPropertyPath ;
85- $ this ->readInfoExtractor = $ this ->writeInfoExtractor = new ReflectionExtractor (
86- ['set ' ],
87- ['get ' , 'is ' , 'has ' , 'can ' ],
88- ['add ' , 'remove ' ],
89- false ,
90- ReflectionExtractor::ALLOW_PUBLIC
91- );
85+ $ this ->readInfoExtractor = $ readInfoExtractor ?? new ReflectionExtractor ([], null , null , false );
86+ $ this ->writeInfoExtractor = $ writeInfoExtractor ?? new ReflectionExtractor (['set ' ], null , null , false );
9287 }
9388
9489 /**
@@ -391,34 +386,25 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid
391386 $ access = $ this ->getReadInfo ($ class , $ property );
392387
393388 if (null !== $ access ) {
394- if (PropertyReadInfo::TYPE_METHOD === $ access ->getType ()) {
395- $ result [self ::VALUE ] = $ object ->{$ access ->getName ()}();
396- }
389+ $ name = $ access ->getName ();
390+ $ type = $ access ->getType ();
397391
398- if (PropertyReadInfo::TYPE_PROPERTY === $ access ->getType ()) {
399- $ result [self ::VALUE ] = $ object ->{$ access ->getName ()};
392+ if (PropertyReadInfo::TYPE_METHOD === $ type ) {
393+ $ result [self ::VALUE ] = $ object ->$ name ();
394+ } elseif (PropertyReadInfo::TYPE_PROPERTY === $ type ) {
395+ $ result [self ::VALUE ] = $ object ->$ name ;
400396
401397 if (isset ($ zval [self ::REF ]) && $ access ->canBeReference ()) {
402- $ result [self ::REF ] = &$ object ->{ $ access -> getName ()} ;
398+ $ result [self ::REF ] = &$ object ->$ name ;
403399 }
404400 }
405401 } elseif ($ object instanceof \stdClass && property_exists ($ object , $ property )) {
406- // Needed to support \stdClass instances. We need to explicitly
407- // exclude $access[self::ACCESS_HAS_PROPERTY], otherwise if
408- // a *protected* property was found on the class, property_exists()
409- // returns true, consequently the following line will result in a
410- // fatal error.
411-
412402 $ result [self ::VALUE ] = $ object ->$ property ;
413403 if (isset ($ zval [self ::REF ])) {
414404 $ result [self ::REF ] = &$ object ->$ property ;
415405 }
416406 } elseif (!$ ignoreInvalidProperty ) {
417- throw new NoSuchPropertyException (sprintf (
418- 'Can get a way to read the property "%s" in class "%s". ' ,
419- $ property ,
420- $ class
421- ));
407+ throw new NoSuchPropertyException (sprintf ('Can \'t get a way to read the property "%s" in class "%s". ' , $ property , $ class ));
422408 }
423409
424410 // Objects are always passed around by reference
@@ -494,46 +480,39 @@ private function writeProperty(array $zval, string $property, $value)
494480 $ class = \get_class ($ object );
495481 $ mutator = $ this ->getWriteInfo ($ class , $ property , $ value );
496482
497- if (null !== $ mutator ) {
498- if (PropertyWriteInfo::TYPE_METHOD === $ mutator ->getType ()) {
499- $ object ->{$ mutator ->getName ()}($ value );
500- }
483+ if (PropertyWriteInfo::TYPE_NONE !== $ mutator ->getType ()) {
484+ $ type = $ mutator ->getType ();
501485
502- if (PropertyWriteInfo::TYPE_PROPERTY === $ mutator ->getType ()) {
486+ if (PropertyWriteInfo::TYPE_METHOD === $ type ) {
487+ $ object ->{$ mutator ->getName ()}($ value );
488+ } elseif (PropertyWriteInfo::TYPE_PROPERTY === $ type ) {
503489 $ object ->{$ mutator ->getName ()} = $ value ;
504- }
505-
506- if (PropertyWriteInfo::TYPE_ADDER_AND_REMOVER === $ mutator ->getType ()) {
490+ } elseif (PropertyWriteInfo::TYPE_ADDER_AND_REMOVER === $ type ) {
507491 $ this ->writeCollection ($ zval , $ property , $ value , $ mutator ->getAdderInfo (), $ mutator ->getRemoverInfo ());
508492 }
509493 } elseif ($ object instanceof \stdClass && property_exists ($ object , $ property )) {
510- // Needed to support \stdClass instances. We need to explicitly
511- // exclude $access[self::ACCESS_HAS_PROPERTY], otherwise if
512- // a *protected* property was found on the class, property_exists()
513- // returns true, consequently the following line will result in a
514- // fatal error.
515-
516494 $ object ->$ property = $ value ;
517- } else {
495+ } elseif (!$ this ->ignoreInvalidProperty ) {
496+ if ($ mutator ->hasErrors ()) {
497+ throw new NoSuchPropertyException (implode ('. ' , $ mutator ->getErrors ()).'. ' );
498+ }
499+
518500 throw new NoSuchPropertyException (sprintf ('Could not determine access type for property "%s" in class "%s". ' , $ property , \get_class ($ object )));
519501 }
520502 }
521503
522504 /**
523505 * Adjusts a collection-valued property by calling add*() and remove*() methods.
524- *
525- * @param array $zval The array containing the object to write to
526- * @param string $property The property to write
527- * @param iterable $collection The collection to write
528- * @param PropertyWriteInfo $addMethod The add*() method
529- * @param PropertyWriteInfo $removeMethod The remove*() method
530506 */
531507 private function writeCollection (array $ zval , string $ property , iterable $ collection , PropertyWriteInfo $ addMethod , PropertyWriteInfo $ removeMethod )
532508 {
533509 // At this point the add and remove methods have been found
534510 $ previousValue = $ this ->readProperty ($ zval , $ property );
535511 $ previousValue = $ previousValue [self ::VALUE ];
536512
513+ $ removeMethodName = $ removeMethod ->getName ();
514+ $ addMethodName = $ addMethod ->getName ();
515+
537516 if ($ previousValue instanceof \Traversable) {
538517 $ previousValue = iterator_to_array ($ previousValue );
539518 }
@@ -544,7 +523,7 @@ private function writeCollection(array $zval, string $property, iterable $collec
544523 foreach ($ previousValue as $ key => $ item ) {
545524 if (!\in_array ($ item , $ collection , true )) {
546525 unset($ previousValue [$ key ]);
547- $ zval [self ::VALUE ]->{ $ removeMethod -> getName ()} ($ item );
526+ $ zval [self ::VALUE ]->$ removeMethodName ($ item );
548527 }
549528 }
550529 } else {
@@ -553,12 +532,12 @@ private function writeCollection(array $zval, string $property, iterable $collec
553532
554533 foreach ($ collection as $ item ) {
555534 if (!$ previousValue || !\in_array ($ item , $ previousValue , true )) {
556- $ zval [self ::VALUE ]->{ $ addMethod -> getName ()} ($ item );
535+ $ zval [self ::VALUE ]->$ addMethodName ($ item );
557536 }
558537 }
559538 }
560539
561- private function getWriteInfo (string $ class , string $ property , $ value ): ? PropertyWriteInfo
540+ private function getWriteInfo (string $ class , string $ property , $ value ): PropertyWriteInfo
562541 {
563542 $ useAdderAndRemover = \is_array ($ value ) || $ value instanceof \Traversable;
564543 $ key = str_replace ('\\' , '. ' , $ class ).'.. ' .$ property .'.. ' .(int ) $ useAdderAndRemover ;
@@ -601,13 +580,13 @@ private function isPropertyWritable($object, string $property): bool
601580
602581 $ mutatorForArray = $ this ->getWriteInfo (\get_class ($ object ), $ property , []);
603582
604- if (null !== $ mutatorForArray || ($ object instanceof \stdClass && property_exists ($ object , $ property ))) {
583+ if (PropertyWriteInfo:: TYPE_NONE !== $ mutatorForArray-> getType () || ($ object instanceof \stdClass && property_exists ($ object , $ property ))) {
605584 return true ;
606585 }
607586
608587 $ mutator = $ this ->getWriteInfo (\get_class ($ object ), $ property , '' );
609588
610- return null !== $ mutator || ($ object instanceof \stdClass && property_exists ($ object , $ property ));
589+ return PropertyWriteInfo:: TYPE_NONE !== $ mutator-> getType () || ($ object instanceof \stdClass && property_exists ($ object , $ property ));
611590 }
612591
613592 /**
0 commit comments