@@ -76,19 +76,14 @@ class PropertyAccessor implements PropertyAccessorInterface
76
76
* Should not be used by application code. Use
77
77
* {@link PropertyAccess::createPropertyAccessor()} instead.
78
78
*/
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 )
80
80
{
81
81
$ this ->magicCall = $ magicCall ;
82
82
$ this ->ignoreInvalidIndices = !$ throwExceptionOnInvalidIndex ;
83
83
$ this ->cacheItemPool = $ cacheItemPool instanceof NullAdapter ? null : $ cacheItemPool ; // Replace the NullAdapter by the null value
84
84
$ 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 (['set ' ], null , null , false );
86
+ $ this ->writeInfoExtractor = $ writeInfoExtractor ?? new ReflectionExtractor (['set ' ], null , null , false );
92
87
}
93
88
94
89
/**
@@ -391,34 +386,25 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid
391
386
$ access = $ this ->getReadInfo ($ class , $ property );
392
387
393
388
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 ();
397
391
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 ;
400
396
401
397
if (isset ($ zval [self ::REF ]) && $ access ->canBeReference ()) {
402
- $ result [self ::REF ] = &$ object ->{ $ access -> getName ()} ;
398
+ $ result [self ::REF ] = &$ object ->$ name ;
403
399
}
404
400
}
405
401
} 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
-
412
402
$ result [self ::VALUE ] = $ object ->$ property ;
413
403
if (isset ($ zval [self ::REF ])) {
414
404
$ result [self ::REF ] = &$ object ->$ property ;
415
405
}
416
406
} 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 get a way to read the property "%s" in class "%s". ' , $ property , $ class ));
422
408
}
423
409
424
410
// Objects are always passed around by reference
@@ -494,46 +480,39 @@ private function writeProperty(array $zval, string $property, $value)
494
480
$ class = \get_class ($ object );
495
481
$ mutator = $ this ->getWriteInfo ($ class , $ property , $ value );
496
482
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 ();
501
485
502
- if (PropertyWriteInfo::TYPE_PROPERTY === $ mutator ->getType ()) {
486
+ if (PropertyWriteInfo::TYPE_METHOD === $ type ) {
487
+ $ object ->{$ mutator ->getName ()}($ value );
488
+ } elseif (PropertyWriteInfo::TYPE_PROPERTY === $ type ) {
503
489
$ object ->{$ mutator ->getName ()} = $ value ;
504
- }
505
-
506
- if (PropertyWriteInfo::TYPE_ADDER_AND_REMOVER === $ mutator ->getType ()) {
490
+ } elseif (PropertyWriteInfo::TYPE_ADDER_AND_REMOVER === $ type ) {
507
491
$ this ->writeCollection ($ zval , $ property , $ value , $ mutator ->getAdderInfo (), $ mutator ->getRemoverInfo ());
508
492
}
509
493
} 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
-
516
494
$ object ->$ property = $ value ;
517
495
} else {
496
+ if ($ mutator ->hasErrors ()) {
497
+ throw new NoSuchPropertyException (implode ('. ' , $ mutator ->getErrors ()).'. ' );
498
+ }
499
+
518
500
throw new NoSuchPropertyException (sprintf ('Could not determine access type for property "%s" in class "%s". ' , $ property , \get_class ($ object )));
519
501
}
520
502
}
521
503
522
504
/**
523
505
* 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
530
506
*/
531
507
private function writeCollection (array $ zval , string $ property , iterable $ collection , PropertyWriteInfo $ addMethod , PropertyWriteInfo $ removeMethod )
532
508
{
533
509
// At this point the add and remove methods have been found
534
510
$ previousValue = $ this ->readProperty ($ zval , $ property );
535
511
$ previousValue = $ previousValue [self ::VALUE ];
536
512
513
+ $ removeMethodName = $ removeMethod ->getName ();
514
+ $ addMethodName = $ addMethod ->getName ();
515
+
537
516
if ($ previousValue instanceof \Traversable) {
538
517
$ previousValue = iterator_to_array ($ previousValue );
539
518
}
@@ -544,7 +523,7 @@ private function writeCollection(array $zval, string $property, iterable $collec
544
523
foreach ($ previousValue as $ key => $ item ) {
545
524
if (!\in_array ($ item , $ collection , true )) {
546
525
unset($ previousValue [$ key ]);
547
- $ zval [self ::VALUE ]->{ $ removeMethod -> getName ()} ($ item );
526
+ $ zval [self ::VALUE ]->$ removeMethodName ($ item );
548
527
}
549
528
}
550
529
} else {
@@ -553,12 +532,12 @@ private function writeCollection(array $zval, string $property, iterable $collec
553
532
554
533
foreach ($ collection as $ item ) {
555
534
if (!$ previousValue || !\in_array ($ item , $ previousValue , true )) {
556
- $ zval [self ::VALUE ]->{ $ addMethod -> getName ()} ($ item );
535
+ $ zval [self ::VALUE ]->$ addMethodName ($ item );
557
536
}
558
537
}
559
538
}
560
539
561
- private function getWriteInfo (string $ class , string $ property , $ value ): ? PropertyWriteInfo
540
+ private function getWriteInfo (string $ class , string $ property , $ value ): PropertyWriteInfo
562
541
{
563
542
$ useAdderAndRemover = \is_array ($ value ) || $ value instanceof \Traversable;
564
543
$ key = str_replace ('\\' , '. ' , $ class ).'.. ' .$ property .'.. ' .(int ) $ useAdderAndRemover ;
@@ -601,13 +580,13 @@ private function isPropertyWritable($object, string $property): bool
601
580
602
581
$ mutatorForArray = $ this ->getWriteInfo (\get_class ($ object ), $ property , []);
603
582
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 ))) {
605
584
return true ;
606
585
}
607
586
608
587
$ mutator = $ this ->getWriteInfo (\get_class ($ object ), $ property , '' );
609
588
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 ));
611
590
}
612
591
613
592
/**
0 commit comments