@@ -400,6 +400,7 @@ private function writeIndex(&$array, $index, $value)
400400 *
401401 * @throws NoSuchPropertyException If the property does not exist or is not
402402 * public.
403+ * @throws UnexpectedTypeException
403404 */
404405 private function writeProperty (&$ object , $ property , $ singular , $ value )
405406 {
@@ -410,7 +411,7 @@ private function writeProperty(&$object, $property, $singular, $value)
410411 $ access = $ this ->getWriteAccessInfo ($ object , $ property , $ singular , $ value );
411412
412413 if (self ::ACCESS_TYPE_METHOD === $ access [self ::ACCESS_TYPE ]) {
413- $ object ->{ $ access [self ::ACCESS_NAME ]}( $ value );
414+ $ this -> callMethod ( $ object , $ access [self ::ACCESS_NAME ], $ value );
414415 } elseif (self ::ACCESS_TYPE_PROPERTY === $ access [self ::ACCESS_TYPE ]) {
415416 $ object ->{$ access [self ::ACCESS_NAME ]} = $ value ;
416417 } elseif (self ::ACCESS_TYPE_ADDER_AND_REMOVER === $ access [self ::ACCESS_TYPE ]) {
@@ -457,12 +458,78 @@ private function writeProperty(&$object, $property, $singular, $value)
457458
458459 $ object ->$ property = $ value ;
459460 } elseif (self ::ACCESS_TYPE_MAGIC === $ access [self ::ACCESS_TYPE ]) {
460- $ object ->{ $ access [self ::ACCESS_NAME ]}( $ value );
461+ $ this -> callMethod ( $ object , $ access [self ::ACCESS_NAME ], $ value );
461462 } else {
462463 throw new NoSuchPropertyException ($ access [self ::ACCESS_NAME ]);
463464 }
464465 }
465466
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+
466533 /**
467534 * Guesses how to write the property value.
468535 *
0 commit comments