@@ -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,66 @@ 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
+ self ::$ previousErrorHandler = set_error_handler (array (__CLASS__ , 'handleError ' ));
138
+ }
136
139
137
- if ($ overwrite ) {
138
- $ property = $ propertyPath ->getElement ($ i );
139
- //$singular = $propertyPath->singulars[$i];
140
- $ singular = null ;
140
+ for ($ i = count ($ propertyValues ) - 1 ; $ i >= 0 ; --$ i ) {
141
+ $ objectOrArray = &$ propertyValues [$ i ][self ::VALUE ];
141
142
142
- if ($ propertyPath ->isIndex ($ i )) {
143
- $ this ->writeIndex ($ objectOrArray , $ property , $ value );
144
- } else {
145
- $ this ->writeProperty ($ objectOrArray , $ property , $ singular , $ value );
143
+ if ($ overwrite ) {
144
+ $ property = $ propertyPath ->getElement ($ i );
145
+ //$singular = $propertyPath->singulars[$i];
146
+ $ singular = null ;
147
+
148
+ if ($ propertyPath ->isIndex ($ i )) {
149
+ $ this ->writeIndex ($ objectOrArray , $ property , $ value );
150
+ } else {
151
+ $ this ->writeProperty ($ objectOrArray , $ property , $ singular , $ value );
152
+ }
146
153
}
154
+
155
+ $ value = &$ objectOrArray ;
156
+ $ overwrite = !$ propertyValues [$ i ][self ::IS_REF ];
157
+ }
158
+ } catch (\TypeError $ e ) {
159
+ try {
160
+ self ::throwUnexpectedTypeException ($ e ->getMessage (), $ e ->getTrace (), 0 );
161
+ } catch (UnexpectedTypeException $ e ) {
147
162
}
163
+ } catch (\Exception $ e ) {
164
+ } catch (\Throwable $ e ) {
165
+ }
166
+
167
+ if (PHP_VERSION_ID < 70000 ) {
168
+ restore_error_handler ();
169
+ self ::$ previousErrorHandler = null ;
170
+ }
171
+ if (isset ($ e )) {
172
+ throw $ e ;
173
+ }
174
+ }
148
175
149
- $ value = &$ objectOrArray ;
150
- $ overwrite = !$ propertyValues [$ i ][self ::IS_REF ];
176
+ /**
177
+ * @internal
178
+ */
179
+ public static function handleError ($ type , $ message , $ file , $ line , $ context )
180
+ {
181
+ if (E_RECOVERABLE_ERROR === $ type ) {
182
+ self ::throwUnexpectedTypeException ($ message , debug_backtrace (false ), 1 );
183
+ }
184
+
185
+ return null !== self ::$ previousErrorHandler && false !== call_user_func (self ::$ previousErrorHandler , $ type , $ message , $ file , $ line , $ context );
186
+ }
187
+
188
+ private static function throwUnexpectedTypeException ($ message , $ trace , $ i )
189
+ {
190
+ if (isset ($ trace [$ i ]['file ' ]) && __FILE__ === $ trace [$ i ]['file ' ]) {
191
+ $ pos = strpos ($ message , $ delim = 'must be of the type ' ) ?: strpos ($ message , $ delim = 'must be an instance of ' );
192
+ $ pos += strlen ($ delim );
193
+
194
+ throw new UnexpectedTypeException ($ trace [$ i ]['args ' ][0 ], substr ($ message , $ pos , strpos ($ message , ', ', $ pos ) - $ pos ));
151
195
}
152
196
}
153
197
@@ -398,9 +442,7 @@ private function writeIndex(&$array, $index, $value)
398
442
* @param string|null $singular The singular form of the property name or null
399
443
* @param mixed $value The value to write
400
444
*
401
- * @throws NoSuchPropertyException If the property does not exist or is not
402
- * public.
403
- * @throws UnexpectedTypeException
445
+ * @throws NoSuchPropertyException If the property does not exist or is not public.
404
446
*/
405
447
private function writeProperty (&$ object , $ property , $ singular , $ value )
406
448
{
@@ -411,7 +453,7 @@ private function writeProperty(&$object, $property, $singular, $value)
411
453
$ access = $ this ->getWriteAccessInfo ($ object , $ property , $ singular , $ value );
412
454
413
455
if (self ::ACCESS_TYPE_METHOD === $ access [self ::ACCESS_TYPE ]) {
414
- $ this -> callMethod ( $ object , $ access [self ::ACCESS_NAME ], $ value );
456
+ $ object ->{ $ access [self ::ACCESS_NAME ]}( $ value );
415
457
} elseif (self ::ACCESS_TYPE_PROPERTY === $ access [self ::ACCESS_TYPE ]) {
416
458
$ object ->{$ access [self ::ACCESS_NAME ]} = $ value ;
417
459
} elseif (self ::ACCESS_TYPE_ADDER_AND_REMOVER === $ access [self ::ACCESS_TYPE ]) {
@@ -458,78 +500,12 @@ private function writeProperty(&$object, $property, $singular, $value)
458
500
459
501
$ object ->$ property = $ value ;
460
502
} elseif (self ::ACCESS_TYPE_MAGIC === $ access [self ::ACCESS_TYPE ]) {
461
- $ this -> callMethod ( $ object , $ access [self ::ACCESS_NAME ], $ value );
503
+ $ object ->{ $ access [self ::ACCESS_NAME ]}( $ value );
462
504
} else {
463
505
throw new NoSuchPropertyException ($ access [self ::ACCESS_NAME ]);
464
506
}
465
507
}
466
508
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
509
/**
534
510
* Guesses how to write the property value.
535
511
*
0 commit comments