@@ -89,6 +89,7 @@ class PropertyAccessor implements PropertyAccessorInterface
89
89
private $ magicCall ;
90
90
private $ readPropertyCache = array ();
91
91
private $ writePropertyCache = array ();
92
+ private static $ previousErrorHandler ;
92
93
93
94
/**
94
95
* Should not be used by application code. Use
@@ -131,23 +132,67 @@ public function setValue(&$objectOrArray, $propertyPath, $value)
131
132
self ::IS_REF => true ,
132
133
));
133
134
134
- for ($ i = count ($ propertyValues ) - 1 ; $ i >= 0 ; --$ i ) {
135
- $ objectOrArray = &$ propertyValues [$ i ][self ::VALUE ];
135
+ try {
136
+ if (PHP_VERSION_ID < 70000 ) {
137
+ static $ errorHandler = array (__CLASS__ , 'handleError ' );
138
+ self ::$ previousErrorHandler = set_error_handler ($ errorHandler );
139
+ }
136
140
137
- if ($ overwrite ) {
138
- $ property = $ propertyPath ->getElement ($ i );
139
- //$singular = $propertyPath->singulars[$i];
140
- $ singular = null ;
141
+ for ($ i = count ($ propertyValues ) - 1 ; $ i >= 0 ; --$ i ) {
142
+ $ objectOrArray = &$ propertyValues [$ i ][self ::VALUE ];
141
143
142
- if ($ propertyPath ->isIndex ($ i )) {
143
- $ this ->writeIndex ($ objectOrArray , $ property , $ value );
144
- } else {
145
- $ this ->writeProperty ($ objectOrArray , $ property , $ singular , $ value );
144
+ if ($ overwrite ) {
145
+ $ property = $ propertyPath ->getElement ($ i );
146
+ //$singular = $propertyPath->singulars[$i];
147
+ $ singular = null ;
148
+
149
+ if ($ propertyPath ->isIndex ($ i )) {
150
+ $ this ->writeIndex ($ objectOrArray , $ property , $ value );
151
+ } else {
152
+ $ this ->writeProperty ($ objectOrArray , $ property , $ singular , $ value );
153
+ }
146
154
}
155
+
156
+ $ value = &$ objectOrArray ;
157
+ $ overwrite = !$ propertyValues [$ i ][self ::IS_REF ];
158
+ }
159
+ } catch (\TypeError $ e ) {
160
+ try {
161
+ self ::throwUnexpectedTypeException ($ e ->getMessage (), $ e ->getTrace (), 0 );
162
+ } catch (UnexpectedTypeException $ e ) {
147
163
}
164
+ } catch (\Exception $ e ) {
165
+ } catch (\Throwable $ e ) {
166
+ }
167
+
168
+ if (PHP_VERSION_ID < 70000 ) {
169
+ restore_error_handler ();
170
+ self ::$ previousErrorHandler = null ;
171
+ }
172
+ if (isset ($ e )) {
173
+ throw $ e ;
174
+ }
175
+ }
148
176
149
- $ value = &$ objectOrArray ;
150
- $ overwrite = !$ propertyValues [$ i ][self ::IS_REF ];
177
+ /**
178
+ * @internal
179
+ */
180
+ public static function handleError ($ type , $ message , $ file , $ line , $ context )
181
+ {
182
+ if (E_RECOVERABLE_ERROR === $ type ) {
183
+ self ::throwUnexpectedTypeException ($ message , debug_backtrace (false ), 1 );
184
+ }
185
+
186
+ return null !== self ::$ previousErrorHandler && false !== call_user_func (self ::$ previousErrorHandler , $ type , $ message , $ file , $ line , $ context );
187
+ }
188
+
189
+ private static function throwUnexpectedTypeException ($ message , $ trace , $ i )
190
+ {
191
+ if (isset ($ trace [$ i ]['file ' ]) && __FILE__ === $ trace [$ i ]['file ' ]) {
192
+ $ pos = strpos ($ message , $ delim = 'must be of the type ' ) ?: strpos ($ message , $ delim = 'must be an instance of ' );
193
+ $ pos += strlen ($ delim );
194
+
195
+ throw new UnexpectedTypeException ($ trace [$ i ]['args ' ][0 ], substr ($ message , $ pos , strpos ($ message , ', ' , $ pos ) - $ pos ));
151
196
}
152
197
}
153
198
@@ -398,9 +443,7 @@ private function writeIndex(&$array, $index, $value)
398
443
* @param string|null $singular The singular form of the property name or null
399
444
* @param mixed $value The value to write
400
445
*
401
- * @throws NoSuchPropertyException If the property does not exist or is not
402
- * public.
403
- * @throws UnexpectedTypeException
446
+ * @throws NoSuchPropertyException If the property does not exist or is not public.
404
447
*/
405
448
private function writeProperty (&$ object , $ property , $ singular , $ value )
406
449
{
@@ -411,7 +454,7 @@ private function writeProperty(&$object, $property, $singular, $value)
411
454
$ access = $ this ->getWriteAccessInfo ($ object , $ property , $ singular , $ value );
412
455
413
456
if (self ::ACCESS_TYPE_METHOD === $ access [self ::ACCESS_TYPE ]) {
414
- $ this -> callMethod ( $ object , $ access [self ::ACCESS_NAME ], $ value );
457
+ $ object ->{ $ access [self ::ACCESS_NAME ]}( $ value );
415
458
} elseif (self ::ACCESS_TYPE_PROPERTY === $ access [self ::ACCESS_TYPE ]) {
416
459
$ object ->{$ access [self ::ACCESS_NAME ]} = $ value ;
417
460
} elseif (self ::ACCESS_TYPE_ADDER_AND_REMOVER === $ access [self ::ACCESS_TYPE ]) {
@@ -458,78 +501,12 @@ private function writeProperty(&$object, $property, $singular, $value)
458
501
459
502
$ object ->$ property = $ value ;
460
503
} elseif (self ::ACCESS_TYPE_MAGIC === $ access [self ::ACCESS_TYPE ]) {
461
- $ this -> callMethod ( $ object , $ access [self ::ACCESS_NAME ], $ value );
504
+ $ object ->{ $ access [self ::ACCESS_NAME ]}( $ value );
462
505
} else {
463
506
throw new NoSuchPropertyException ($ access [self ::ACCESS_NAME ]);
464
507
}
465
508
}
466
509
467
- /**
468
- * Throws a {@see UnexpectedTypeException} as in PHP 7 when using PHP 5.
469
- *
470
- * @param object $object
471
- * @param string $method
472
- * @param mixed $value
473
- *
474
- * @throws UnexpectedTypeException
475
- * @throws \Exception
476
- */
477
- private function callMethod ($ object , $ method , $ value ) {
478
- if (PHP_MAJOR_VERSION >= 7 ) {
479
- try {
480
- $ object ->{$ method }($ value );
481
- } catch (\TypeError $ e ) {
482
- throw $ this ->createUnexpectedTypeException ($ object , $ method , $ value );
483
- }
484
-
485
- return ;
486
- }
487
-
488
- $ that = $ this ;
489
- set_error_handler (function ($ errno , $ errstr ) use ($ object , $ method , $ value , $ that ) {
490
- if (E_RECOVERABLE_ERROR === $ errno && false !== strpos ($ errstr , sprintf ('passed to %s::%s() must ' , get_class ($ object ), $ method ))) {
491
- throw $ that ->createUnexpectedTypeException ($ object , $ method , $ value );
492
- }
493
-
494
- return false ;
495
- });
496
-
497
- try {
498
- $ object ->{$ method }($ value );
499
- restore_error_handler ();
500
- } catch (\Exception $ e ) {
501
- // Cannot use finally in 5.5 because of https://bugs.php.net/bug.php?id=67047
502
- restore_error_handler ();
503
-
504
- throw $ e ;
505
- }
506
- }
507
-
508
- /**
509
- * Creates an UnexpectedTypeException.
510
- *
511
- * @param object $object
512
- * @param string $method
513
- * @param mixed $value
514
- *
515
- * @return UnexpectedTypeException
516
- */
517
- private function createUnexpectedTypeException ($ object , $ method , $ value )
518
- {
519
- $ reflectionMethod = new \ReflectionMethod ($ object , $ method );
520
- $ parameters = $ reflectionMethod ->getParameters ();
521
-
522
- $ expectedType = 'unknown ' ;
523
- if (isset ($ parameters [0 ])) {
524
- $ class = $ parameters [0 ]->getClass ();
525
- if (null !== $ class ) {
526
- $ expectedType = $ class ->getName ();
527
- }
528
- }
529
-
530
- return new UnexpectedTypeException ($ value , $ expectedType );
531
- }
532
-
533
510
/**
534
511
* Guesses how to write the property value.
535
512
*
0 commit comments