diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 3b9b49490da58..cb00c093ceef1 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -89,6 +89,7 @@ class PropertyAccessor implements PropertyAccessorInterface private $magicCall; private $readPropertyCache = array(); private $writePropertyCache = array(); + private static $previousErrorHandler; /** * Should not be used by application code. Use @@ -131,23 +132,66 @@ public function setValue(&$objectOrArray, $propertyPath, $value) self::IS_REF => true, )); - for ($i = count($propertyValues) - 1; $i >= 0; --$i) { - $objectOrArray = &$propertyValues[$i][self::VALUE]; + try { + if (PHP_VERSION_ID < 70000) { + self::$previousErrorHandler = set_error_handler(array(__CLASS__, 'handleError')); + } - if ($overwrite) { - $property = $propertyPath->getElement($i); - //$singular = $propertyPath->singulars[$i]; - $singular = null; + for ($i = count($propertyValues) - 1; $i >= 0; --$i) { + $objectOrArray = &$propertyValues[$i][self::VALUE]; - if ($propertyPath->isIndex($i)) { - $this->writeIndex($objectOrArray, $property, $value); - } else { - $this->writeProperty($objectOrArray, $property, $singular, $value); + if ($overwrite) { + $property = $propertyPath->getElement($i); + //$singular = $propertyPath->singulars[$i]; + $singular = null; + + if ($propertyPath->isIndex($i)) { + $this->writeIndex($objectOrArray, $property, $value); + } else { + $this->writeProperty($objectOrArray, $property, $singular, $value); + } } + + $value = &$objectOrArray; + $overwrite = !$propertyValues[$i][self::IS_REF]; + } + } catch (\TypeError $e) { + try { + self::throwUnexpectedTypeException($e->getMessage(), $e->getTrace(), 0); + } catch (UnexpectedTypeException $e) { } + } catch (\Exception $e) { + } catch (\Throwable $e) { + } - $value = &$objectOrArray; - $overwrite = !$propertyValues[$i][self::IS_REF]; + if (PHP_VERSION_ID < 70000) { + restore_error_handler(); + self::$previousErrorHandler = null; + } + if (isset($e)) { + throw $e; + } + } + + /** + * @internal + */ + public static function handleError($type, $message, $file, $line, $context) + { + if (E_RECOVERABLE_ERROR === $type) { + self::throwUnexpectedTypeException($message, debug_backtrace(false), 1); + } + + return null !== self::$previousErrorHandler && false !== call_user_func(self::$previousErrorHandler, $type, $message, $file, $line, $context); + } + + private static function throwUnexpectedTypeException($message, $trace, $i) + { + if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file']) { + $pos = strpos($message, $delim = 'must be of the type ') ?: strpos($message, $delim = 'must be an instance of '); + $pos += strlen($delim); + + throw new UnexpectedTypeException($trace[$i]['args'][0], substr($message, $pos, strpos($message, ',', $pos) - $pos)); } } @@ -398,8 +442,7 @@ private function writeIndex(&$array, $index, $value) * @param string|null $singular The singular form of the property name or null * @param mixed $value The value to write * - * @throws NoSuchPropertyException If the property does not exist or is not - * public. + * @throws NoSuchPropertyException If the property does not exist or is not public. */ private function writeProperty(&$object, $property, $singular, $value) { diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php b/src/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php index ecedabc134ef4..90f69b39259ff 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php @@ -44,8 +44,7 @@ interface PropertyAccessorInterface * @param mixed $value The value to set at the end of the property path * * @throws Exception\NoSuchPropertyException If a property does not exist or is not public. - * @throws Exception\UnexpectedTypeException If a value within the path is neither object - * nor array + * @throws Exception\UnexpectedTypeException If a value within the path is neither object nor array. */ public function setValue(&$objectOrArray, $propertyPath, $value); diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TypeHinted.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TypeHinted.php new file mode 100644 index 0000000000000..ca4c5745ae06c --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TypeHinted.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class TypeHinted +{ + private $date; + + public function setDate(\DateTime $date) + { + $this->date = $date; + } + + public function getDate() + { + return $this->date; + } +} diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 51bc6eabc2af1..85ea84802790d 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -16,6 +16,7 @@ use Symfony\Component\PropertyAccess\Tests\Fixtures\Magician; use Symfony\Component\PropertyAccess\Tests\Fixtures\MagicianCall; use Symfony\Component\PropertyAccess\Tests\Fixtures\Ticket5775Object; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TypeHinted; class PropertyAccessorTest extends \PHPUnit_Framework_TestCase { @@ -403,4 +404,22 @@ public function getValidPropertyPaths() array(array('root' => array('index' => array())), '[root][index][firstName]', null), ); } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + * @expectedExceptionMessage Expected argument of type "DateTime", "string" given + */ + public function testThrowTypeError() + { + $this->propertyAccessor->setValue(new TypeHinted(), 'date', 'This is a string, \DateTime excepted.'); + } + + public function testSetTypeHint() + { + $date = new \DateTime(); + $object = new TypeHinted(); + + $this->propertyAccessor->setValue($object, 'date', $date); + $this->assertSame($date, $object->getDate()); + } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy