Deprecated: Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 58

Deprecated: Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 76
Symfony Profiler

vendor/symfony/property-info/Extractor/ReflectionExtractor.php line 86

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\PropertyInfo\Extractor;
  11. use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
  12. use Symfony\Component\PropertyInfo\PropertyInitializableExtractorInterface;
  13. use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
  14. use Symfony\Component\PropertyInfo\PropertyReadInfo;
  15. use Symfony\Component\PropertyInfo\PropertyReadInfoExtractorInterface;
  16. use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
  17. use Symfony\Component\PropertyInfo\PropertyWriteInfo;
  18. use Symfony\Component\PropertyInfo\PropertyWriteInfoExtractorInterface;
  19. use Symfony\Component\PropertyInfo\Type;
  20. use Symfony\Component\String\Inflector\EnglishInflector;
  21. use Symfony\Component\String\Inflector\InflectorInterface;
  22. /**
  23.  * Extracts data using the reflection API.
  24.  *
  25.  * @author Kévin Dunglas <dunglas@gmail.com>
  26.  *
  27.  * @final
  28.  */
  29. class ReflectionExtractor implements PropertyListExtractorInterfacePropertyTypeExtractorInterfacePropertyAccessExtractorInterfacePropertyInitializableExtractorInterfacePropertyReadInfoExtractorInterfacePropertyWriteInfoExtractorInterfaceConstructorArgumentTypeExtractorInterface
  30. {
  31.     /**
  32.      * @internal
  33.      */
  34.     public static $defaultMutatorPrefixes = ['add''remove''set'];
  35.     /**
  36.      * @internal
  37.      */
  38.     public static $defaultAccessorPrefixes = ['get''is''has''can'];
  39.     /**
  40.      * @internal
  41.      */
  42.     public static $defaultArrayMutatorPrefixes = ['add''remove'];
  43.     public const ALLOW_PRIVATE 1;
  44.     public const ALLOW_PROTECTED 2;
  45.     public const ALLOW_PUBLIC 4;
  46.     /** @var int Allow none of the magic methods */
  47.     public const DISALLOW_MAGIC_METHODS 0;
  48.     /** @var int Allow magic __get methods */
  49.     public const ALLOW_MAGIC_GET << 0;
  50.     /** @var int Allow magic __set methods */
  51.     public const ALLOW_MAGIC_SET << 1;
  52.     /** @var int Allow magic __call methods */
  53.     public const ALLOW_MAGIC_CALL << 2;
  54.     private const MAP_TYPES = [
  55.         'integer' => Type::BUILTIN_TYPE_INT,
  56.         'boolean' => Type::BUILTIN_TYPE_BOOL,
  57.         'double' => Type::BUILTIN_TYPE_FLOAT,
  58.     ];
  59.     private $mutatorPrefixes;
  60.     private $accessorPrefixes;
  61.     private $arrayMutatorPrefixes;
  62.     private $enableConstructorExtraction;
  63.     private $methodReflectionFlags;
  64.     private $magicMethodsFlags;
  65.     private $propertyReflectionFlags;
  66.     private $inflector;
  67.     private $arrayMutatorPrefixesFirst;
  68.     private $arrayMutatorPrefixesLast;
  69.     /**
  70.      * @param string[]|null $mutatorPrefixes
  71.      * @param string[]|null $accessorPrefixes
  72.      * @param string[]|null $arrayMutatorPrefixes
  73.      */
  74.     public function __construct(array $mutatorPrefixes null, array $accessorPrefixes null, array $arrayMutatorPrefixes nullbool $enableConstructorExtraction trueint $accessFlags self::ALLOW_PUBLICInflectorInterface $inflector nullint $magicMethodsFlags self::ALLOW_MAGIC_GET self::ALLOW_MAGIC_SET)
  75.     {
  76.         $this->mutatorPrefixes $mutatorPrefixes ?? self::$defaultMutatorPrefixes;
  77.         $this->accessorPrefixes $accessorPrefixes ?? self::$defaultAccessorPrefixes;
  78.         $this->arrayMutatorPrefixes $arrayMutatorPrefixes ?? self::$defaultArrayMutatorPrefixes;
  79.         $this->enableConstructorExtraction $enableConstructorExtraction;
  80.         $this->methodReflectionFlags $this->getMethodsFlags($accessFlags);
  81.         $this->propertyReflectionFlags $this->getPropertyFlags($accessFlags);
  82.         $this->magicMethodsFlags $magicMethodsFlags;
  83.         $this->inflector $inflector ?? new EnglishInflector();
  84.         $this->arrayMutatorPrefixesFirst array_merge($this->arrayMutatorPrefixesarray_diff($this->mutatorPrefixes$this->arrayMutatorPrefixes));
  85.         $this->arrayMutatorPrefixesLast array_reverse($this->arrayMutatorPrefixesFirst);
  86.     }
  87.     /**
  88.      * {@inheritdoc}
  89.      */
  90.     public function getProperties(string $class, array $context = []): ?array
  91.     {
  92.         try {
  93.             $reflectionClass = new \ReflectionClass($class);
  94.         } catch (\ReflectionException $e) {
  95.             return null;
  96.         }
  97.         $reflectionProperties $reflectionClass->getProperties();
  98.         $properties = [];
  99.         foreach ($reflectionProperties as $reflectionProperty) {
  100.             if ($reflectionProperty->getModifiers() & $this->propertyReflectionFlags) {
  101.                 $properties[$reflectionProperty->name] = $reflectionProperty->name;
  102.             }
  103.         }
  104.         foreach ($reflectionClass->getMethods($this->methodReflectionFlags) as $reflectionMethod) {
  105.             if ($reflectionMethod->isStatic()) {
  106.                 continue;
  107.             }
  108.             $propertyName $this->getPropertyName($reflectionMethod->name$reflectionProperties);
  109.             if (!$propertyName || isset($properties[$propertyName])) {
  110.                 continue;
  111.             }
  112.             if ($reflectionClass->hasProperty($lowerCasedPropertyName lcfirst($propertyName)) || (!$reflectionClass->hasProperty($propertyName) && !preg_match('/^[A-Z]{2,}/'$propertyName))) {
  113.                 $propertyName $lowerCasedPropertyName;
  114.             }
  115.             $properties[$propertyName] = $propertyName;
  116.         }
  117.         return $properties array_values($properties) : null;
  118.     }
  119.     /**
  120.      * {@inheritdoc}
  121.      */
  122.     public function getTypes(string $classstring $property, array $context = []): ?array
  123.     {
  124.         if ($fromMutator $this->extractFromMutator($class$property)) {
  125.             return $fromMutator;
  126.         }
  127.         if ($fromAccessor $this->extractFromAccessor($class$property)) {
  128.             return $fromAccessor;
  129.         }
  130.         if (
  131.             ($context['enable_constructor_extraction'] ?? $this->enableConstructorExtraction) &&
  132.             $fromConstructor $this->extractFromConstructor($class$property)
  133.         ) {
  134.             return $fromConstructor;
  135.         }
  136.         if ($fromPropertyDeclaration $this->extractFromPropertyDeclaration($class$property)) {
  137.             return $fromPropertyDeclaration;
  138.         }
  139.         return null;
  140.     }
  141.     /**
  142.      * {@inheritdoc}
  143.      */
  144.     public function getTypesFromConstructor(string $classstring $property): ?array
  145.     {
  146.         try {
  147.             $reflection = new \ReflectionClass($class);
  148.         } catch (\ReflectionException $e) {
  149.             return null;
  150.         }
  151.         if (!$reflectionConstructor $reflection->getConstructor()) {
  152.             return null;
  153.         }
  154.         if (!$reflectionParameter $this->getReflectionParameterFromConstructor($property$reflectionConstructor)) {
  155.             return null;
  156.         }
  157.         if (!$reflectionType $reflectionParameter->getType()) {
  158.             return null;
  159.         }
  160.         if (!$types $this->extractFromReflectionType($reflectionType$reflectionConstructor->getDeclaringClass())) {
  161.             return null;
  162.         }
  163.         return $types;
  164.     }
  165.     private function getReflectionParameterFromConstructor(string $property\ReflectionMethod $reflectionConstructor): ?\ReflectionParameter
  166.     {
  167.         $reflectionParameter null;
  168.         foreach ($reflectionConstructor->getParameters() as $reflectionParameter) {
  169.             if ($reflectionParameter->getName() === $property) {
  170.                 return $reflectionParameter;
  171.             }
  172.         }
  173.         return null;
  174.     }
  175.     /**
  176.      * {@inheritdoc}
  177.      */
  178.     public function isReadable(string $classstring $property, array $context = []): ?bool
  179.     {
  180.         if ($this->isAllowedProperty($class$property)) {
  181.             return true;
  182.         }
  183.         return null !== $this->getReadInfo($class$property$context);
  184.     }
  185.     /**
  186.      * {@inheritdoc}
  187.      */
  188.     public function isWritable(string $classstring $property, array $context = []): ?bool
  189.     {
  190.         if ($this->isAllowedProperty($class$propertytrue)) {
  191.             return true;
  192.         }
  193.         [$reflectionMethod] = $this->getMutatorMethod($class$property);
  194.         return null !== $reflectionMethod;
  195.     }
  196.     /**
  197.      * {@inheritdoc}
  198.      */
  199.     public function isInitializable(string $classstring $property, array $context = []): ?bool
  200.     {
  201.         try {
  202.             $reflectionClass = new \ReflectionClass($class);
  203.         } catch (\ReflectionException $e) {
  204.             return null;
  205.         }
  206.         if (!$reflectionClass->isInstantiable()) {
  207.             return false;
  208.         }
  209.         if ($constructor $reflectionClass->getConstructor()) {
  210.             foreach ($constructor->getParameters() as $parameter) {
  211.                 if ($property === $parameter->name) {
  212.                     return true;
  213.                 }
  214.             }
  215.         } elseif ($parentClass $reflectionClass->getParentClass()) {
  216.             return $this->isInitializable($parentClass->getName(), $property);
  217.         }
  218.         return false;
  219.     }
  220.     /**
  221.      * {@inheritdoc}
  222.      */
  223.     public function getReadInfo(string $classstring $property, array $context = []): ?PropertyReadInfo
  224.     {
  225.         try {
  226.             $reflClass = new \ReflectionClass($class);
  227.         } catch (\ReflectionException $e) {
  228.             return null;
  229.         }
  230.         $allowGetterSetter $context['enable_getter_setter_extraction'] ?? false;
  231.         $magicMethods $context['enable_magic_methods_extraction'] ?? $this->magicMethodsFlags;
  232.         $allowMagicCall = (bool) ($magicMethods self::ALLOW_MAGIC_CALL);
  233.         $allowMagicGet = (bool) ($magicMethods self::ALLOW_MAGIC_GET);
  234.         if (isset($context['enable_magic_call_extraction'])) {
  235.             trigger_deprecation('symfony/property-info''5.2''Using the "enable_magic_call_extraction" context option in "%s()" is deprecated. Use "enable_magic_methods_extraction" instead.'__METHOD__);
  236.             $allowMagicCall $context['enable_magic_call_extraction'] ?? false;
  237.         }
  238.         $hasProperty $reflClass->hasProperty($property);
  239.         $camelProp $this->camelize($property);
  240.         $getsetter lcfirst($camelProp); // jQuery style, e.g. read: last(), write: last($item)
  241.         foreach ($this->accessorPrefixes as $prefix) {
  242.             $methodName $prefix.$camelProp;
  243.             if ($reflClass->hasMethod($methodName) && $reflClass->getMethod($methodName)->getModifiers() & $this->methodReflectionFlags && !$reflClass->getMethod($methodName)->getNumberOfRequiredParameters()) {
  244.                 $method $reflClass->getMethod($methodName);
  245.                 return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD$methodName$this->getReadVisiblityForMethod($method), $method->isStatic(), false);
  246.             }
  247.         }
  248.         if ($allowGetterSetter && $reflClass->hasMethod($getsetter) && ($reflClass->getMethod($getsetter)->getModifiers() & $this->methodReflectionFlags)) {
  249.             $method $reflClass->getMethod($getsetter);
  250.             return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD$getsetter$this->getReadVisiblityForMethod($method), $method->isStatic(), false);
  251.         }
  252.         if ($allowMagicGet && $reflClass->hasMethod('__get') && ($reflClass->getMethod('__get')->getModifiers() & $this->methodReflectionFlags)) {
  253.             return new PropertyReadInfo(PropertyReadInfo::TYPE_PROPERTY$propertyPropertyReadInfo::VISIBILITY_PUBLICfalsefalse);
  254.         }
  255.         if ($hasProperty && ($reflClass->getProperty($property)->getModifiers() & $this->propertyReflectionFlags)) {
  256.             $reflProperty $reflClass->getProperty($property);
  257.             return new PropertyReadInfo(PropertyReadInfo::TYPE_PROPERTY$property$this->getReadVisiblityForProperty($reflProperty), $reflProperty->isStatic(), true);
  258.         }
  259.         if ($allowMagicCall && $reflClass->hasMethod('__call') && ($reflClass->getMethod('__call')->getModifiers() & $this->methodReflectionFlags)) {
  260.             return new PropertyReadInfo(PropertyReadInfo::TYPE_METHOD'get'.$camelPropPropertyReadInfo::VISIBILITY_PUBLICfalsefalse);
  261.         }
  262.         return null;
  263.     }
  264.     /**
  265.      * {@inheritdoc}
  266.      */
  267.     public function getWriteInfo(string $classstring $property, array $context = []): ?PropertyWriteInfo
  268.     {
  269.         try {
  270.             $reflClass = new \ReflectionClass($class);
  271.         } catch (\ReflectionException $e) {
  272.             return null;
  273.         }
  274.         $allowGetterSetter $context['enable_getter_setter_extraction'] ?? false;
  275.         $magicMethods $context['enable_magic_methods_extraction'] ?? $this->magicMethodsFlags;
  276.         $allowMagicCall = (bool) ($magicMethods self::ALLOW_MAGIC_CALL);
  277.         $allowMagicSet = (bool) ($magicMethods self::ALLOW_MAGIC_SET);
  278.         if (isset($context['enable_magic_call_extraction'])) {
  279.             trigger_deprecation('symfony/property-info''5.2''Using the "enable_magic_call_extraction" context option in "%s()" is deprecated. Use "enable_magic_methods_extraction" instead.'__METHOD__);
  280.             $allowMagicCall $context['enable_magic_call_extraction'] ?? false;
  281.         }
  282.         $allowConstruct $context['enable_constructor_extraction'] ?? $this->enableConstructorExtraction;
  283.         $allowAdderRemover $context['enable_adder_remover_extraction'] ?? true;
  284.         $camelized $this->camelize($property);
  285.         $constructor $reflClass->getConstructor();
  286.         $singulars $this->inflector->singularize($camelized);
  287.         $errors = [];
  288.         if (null !== $constructor && $allowConstruct) {
  289.             foreach ($constructor->getParameters() as $parameter) {
  290.                 if ($parameter->getName() === $property) {
  291.                     return new PropertyWriteInfo(PropertyWriteInfo::TYPE_CONSTRUCTOR$property);
  292.                 }
  293.             }
  294.         }
  295.         [$adderAccessName$removerAccessName$adderAndRemoverErrors] = $this->findAdderAndRemover($reflClass$singulars);
  296.         if ($allowAdderRemover && null !== $adderAccessName && null !== $removerAccessName) {
  297.             $adderMethod $reflClass->getMethod($adderAccessName);
  298.             $removerMethod $reflClass->getMethod($removerAccessName);
  299.             $mutator = new PropertyWriteInfo(PropertyWriteInfo::TYPE_ADDER_AND_REMOVER);
  300.             $mutator->setAdderInfo(new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD$adderAccessName$this->getWriteVisiblityForMethod($adderMethod), $adderMethod->isStatic()));
  301.             $mutator->setRemoverInfo(new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD$removerAccessName$this->getWriteVisiblityForMethod($removerMethod), $removerMethod->isStatic()));
  302.             return $mutator;
  303.         }
  304.         $errors[] = $adderAndRemoverErrors;
  305.         foreach ($this->mutatorPrefixes as $mutatorPrefix) {
  306.             $methodName $mutatorPrefix.$camelized;
  307.             [$accessible$methodAccessibleErrors] = $this->isMethodAccessible($reflClass$methodName1);
  308.             if (!$accessible) {
  309.                 $errors[] = $methodAccessibleErrors;
  310.                 continue;
  311.             }
  312.             $method $reflClass->getMethod($methodName);
  313.             if (!\in_array($mutatorPrefix$this->arrayMutatorPrefixestrue)) {
  314.                 return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD$methodName$this->getWriteVisiblityForMethod($method), $method->isStatic());
  315.             }
  316.         }
  317.         $getsetter lcfirst($camelized);
  318.         if ($allowGetterSetter) {
  319.             [$accessible$methodAccessibleErrors] = $this->isMethodAccessible($reflClass$getsetter1);
  320.             if ($accessible) {
  321.                 $method $reflClass->getMethod($getsetter);
  322.                 return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD$getsetter$this->getWriteVisiblityForMethod($method), $method->isStatic());
  323.             }
  324.             $errors[] = $methodAccessibleErrors;
  325.         }
  326.         if ($reflClass->hasProperty($property) && ($reflClass->getProperty($property)->getModifiers() & $this->propertyReflectionFlags)) {
  327.             $reflProperty $reflClass->getProperty($property);
  328.             if (\PHP_VERSION_ID 80100 || !$reflProperty->isReadOnly()) {
  329.                 return new PropertyWriteInfo(PropertyWriteInfo::TYPE_PROPERTY$property$this->getWriteVisiblityForProperty($reflProperty), $reflProperty->isStatic());
  330.             }
  331.             $errors[] = [sprintf('The property "%s" in class "%s" is a promoted readonly property.'$property$reflClass->getName())];
  332.             $allowMagicSet $allowMagicCall false;
  333.         }
  334.         if ($allowMagicSet) {
  335.             [$accessible$methodAccessibleErrors] = $this->isMethodAccessible($reflClass'__set'2);
  336.             if ($accessible) {
  337.                 return new PropertyWriteInfo(PropertyWriteInfo::TYPE_PROPERTY$propertyPropertyWriteInfo::VISIBILITY_PUBLICfalse);
  338.             }
  339.             $errors[] = $methodAccessibleErrors;
  340.         }
  341.         if ($allowMagicCall) {
  342.             [$accessible$methodAccessibleErrors] = $this->isMethodAccessible($reflClass'__call'2);
  343.             if ($accessible) {
  344.                 return new PropertyWriteInfo(PropertyWriteInfo::TYPE_METHOD'set'.$camelizedPropertyWriteInfo::VISIBILITY_PUBLICfalse);
  345.             }
  346.             $errors[] = $methodAccessibleErrors;
  347.         }
  348.         if (!$allowAdderRemover && null !== $adderAccessName && null !== $removerAccessName) {
  349.             $errors[] = [sprintf(
  350.                 'The property "%s" in class "%s" can be defined with the methods "%s()" but '.
  351.                 'the new value must be an array or an instance of \Traversable',
  352.                 $property,
  353.                 $reflClass->getName(),
  354.                 implode('()", "', [$adderAccessName$removerAccessName])
  355.             )];
  356.         }
  357.         $noneProperty = new PropertyWriteInfo();
  358.         $noneProperty->setErrors(array_merge([], ...$errors));
  359.         return $noneProperty;
  360.     }
  361.     /**
  362.      * @return Type[]|null
  363.      */
  364.     private function extractFromMutator(string $classstring $property): ?array
  365.     {
  366.         [$reflectionMethod$prefix] = $this->getMutatorMethod($class$property);
  367.         if (null === $reflectionMethod) {
  368.             return null;
  369.         }
  370.         $reflectionParameters $reflectionMethod->getParameters();
  371.         $reflectionParameter $reflectionParameters[0];
  372.         if (!$reflectionType $reflectionParameter->getType()) {
  373.             return null;
  374.         }
  375.         $type $this->extractFromReflectionType($reflectionType$reflectionMethod->getDeclaringClass());
  376.         if (=== \count($type) && \in_array($prefix$this->arrayMutatorPrefixes)) {
  377.             $type = [new Type(Type::BUILTIN_TYPE_ARRAYfalsenulltrue, new Type(Type::BUILTIN_TYPE_INT), $type[0])];
  378.         }
  379.         return $type;
  380.     }
  381.     /**
  382.      * Tries to extract type information from accessors.
  383.      *
  384.      * @return Type[]|null
  385.      */
  386.     private function extractFromAccessor(string $classstring $property): ?array
  387.     {
  388.         [$reflectionMethod$prefix] = $this->getAccessorMethod($class$property);
  389.         if (null === $reflectionMethod) {
  390.             return null;
  391.         }
  392.         if ($reflectionType $reflectionMethod->getReturnType()) {
  393.             return $this->extractFromReflectionType($reflectionType$reflectionMethod->getDeclaringClass());
  394.         }
  395.         if (\in_array($prefix, ['is''can''has'])) {
  396.             return [new Type(Type::BUILTIN_TYPE_BOOL)];
  397.         }
  398.         return null;
  399.     }
  400.     /**
  401.      * Tries to extract type information from constructor.
  402.      *
  403.      * @return Type[]|null
  404.      */
  405.     private function extractFromConstructor(string $classstring $property): ?array
  406.     {
  407.         try {
  408.             $reflectionClass = new \ReflectionClass($class);
  409.         } catch (\ReflectionException $e) {
  410.             return null;
  411.         }
  412.         $constructor $reflectionClass->getConstructor();
  413.         if (!$constructor) {
  414.             return null;
  415.         }
  416.         foreach ($constructor->getParameters() as $parameter) {
  417.             if ($property !== $parameter->name) {
  418.                 continue;
  419.             }
  420.             $reflectionType $parameter->getType();
  421.             return $reflectionType $this->extractFromReflectionType($reflectionType$constructor->getDeclaringClass()) : null;
  422.         }
  423.         if ($parentClass $reflectionClass->getParentClass()) {
  424.             return $this->extractFromConstructor($parentClass->getName(), $property);
  425.         }
  426.         return null;
  427.     }
  428.     private function extractFromPropertyDeclaration(string $classstring $property): ?array
  429.     {
  430.         try {
  431.             $reflectionClass = new \ReflectionClass($class);
  432.             if (\PHP_VERSION_ID >= 70400) {
  433.                 $reflectionProperty $reflectionClass->getProperty($property);
  434.                 $reflectionPropertyType $reflectionProperty->getType();
  435.                 if (null !== $reflectionPropertyType && $types $this->extractFromReflectionType($reflectionPropertyType$reflectionProperty->getDeclaringClass())) {
  436.                     return $types;
  437.                 }
  438.             }
  439.         } catch (\ReflectionException $e) {
  440.             return null;
  441.         }
  442.         $defaultValue $reflectionClass->getDefaultProperties()[$property] ?? null;
  443.         if (null === $defaultValue) {
  444.             return null;
  445.         }
  446.         $type \gettype($defaultValue);
  447.         $type = static::MAP_TYPES[$type] ?? $type;
  448.         return [new Type($type$this->isNullableProperty($class$property), nullType::BUILTIN_TYPE_ARRAY === $type)];
  449.     }
  450.     private function extractFromReflectionType(\ReflectionType $reflectionType\ReflectionClass $declaringClass): array
  451.     {
  452.         $types = [];
  453.         $nullable $reflectionType->allowsNull();
  454.         foreach (($reflectionType instanceof \ReflectionUnionType || $reflectionType instanceof \ReflectionIntersectionType) ? $reflectionType->getTypes() : [$reflectionType] as $type) {
  455.             if (!$type instanceof \ReflectionNamedType) {
  456.                 // Nested composite types are not supported yet.
  457.                 return [];
  458.             }
  459.             $phpTypeOrClass $type->getName();
  460.             if ('null' === $phpTypeOrClass || 'mixed' === $phpTypeOrClass || 'never' === $phpTypeOrClass) {
  461.                 continue;
  462.             }
  463.             if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) {
  464.                 $types[] = new Type(Type::BUILTIN_TYPE_ARRAY$nullablenulltrue);
  465.             } elseif ('void' === $phpTypeOrClass) {
  466.                 $types[] = new Type(Type::BUILTIN_TYPE_NULL$nullable);
  467.             } elseif ($type->isBuiltin()) {
  468.                 $types[] = new Type($phpTypeOrClass$nullable);
  469.             } else {
  470.                 $types[] = new Type(Type::BUILTIN_TYPE_OBJECT$nullable$this->resolveTypeName($phpTypeOrClass$declaringClass));
  471.             }
  472.         }
  473.         return $types;
  474.     }
  475.     private function resolveTypeName(string $name\ReflectionClass $declaringClass): string
  476.     {
  477.         if ('self' === $lcName strtolower($name)) {
  478.             return $declaringClass->name;
  479.         }
  480.         if ('parent' === $lcName && $parent $declaringClass->getParentClass()) {
  481.             return $parent->name;
  482.         }
  483.         return $name;
  484.     }
  485.     private function isNullableProperty(string $classstring $property): bool
  486.     {
  487.         try {
  488.             $reflectionProperty = new \ReflectionProperty($class$property);
  489.             if (\PHP_VERSION_ID >= 70400) {
  490.                 $reflectionPropertyType $reflectionProperty->getType();
  491.                 return null !== $reflectionPropertyType && $reflectionPropertyType->allowsNull();
  492.             }
  493.             return false;
  494.         } catch (\ReflectionException $e) {
  495.             // Return false if the property doesn't exist
  496.         }
  497.         return false;
  498.     }
  499.     private function isAllowedProperty(string $classstring $propertybool $writeAccessRequired false): bool
  500.     {
  501.         try {
  502.             $reflectionProperty = new \ReflectionProperty($class$property);
  503.             if (\PHP_VERSION_ID >= 80100 && $writeAccessRequired && $reflectionProperty->isReadOnly()) {
  504.                 return false;
  505.             }
  506.             return (bool) ($reflectionProperty->getModifiers() & $this->propertyReflectionFlags);
  507.         } catch (\ReflectionException $e) {
  508.             // Return false if the property doesn't exist
  509.         }
  510.         return false;
  511.     }
  512.     /**
  513.      * Gets the accessor method.
  514.      *
  515.      * Returns an array with a the instance of \ReflectionMethod as first key
  516.      * and the prefix of the method as second or null if not found.
  517.      */
  518.     private function getAccessorMethod(string $classstring $property): ?array
  519.     {
  520.         $ucProperty ucfirst($property);
  521.         foreach ($this->accessorPrefixes as $prefix) {
  522.             try {
  523.                 $reflectionMethod = new \ReflectionMethod($class$prefix.$ucProperty);
  524.                 if ($reflectionMethod->isStatic()) {
  525.                     continue;
  526.                 }
  527.                 if (=== $reflectionMethod->getNumberOfRequiredParameters()) {
  528.                     return [$reflectionMethod$prefix];
  529.                 }
  530.             } catch (\ReflectionException $e) {
  531.                 // Return null if the property doesn't exist
  532.             }
  533.         }
  534.         return null;
  535.     }
  536.     /**
  537.      * Returns an array with a the instance of \ReflectionMethod as first key
  538.      * and the prefix of the method as second or null if not found.
  539.      */
  540.     private function getMutatorMethod(string $classstring $property): ?array
  541.     {
  542.         $ucProperty ucfirst($property);
  543.         $ucSingulars $this->inflector->singularize($ucProperty);
  544.         $mutatorPrefixes \in_array($ucProperty$ucSingularstrue) ? $this->arrayMutatorPrefixesLast $this->arrayMutatorPrefixesFirst;
  545.         foreach ($mutatorPrefixes as $prefix) {
  546.             $names = [$ucProperty];
  547.             if (\in_array($prefix$this->arrayMutatorPrefixes)) {
  548.                 $names array_merge($names$ucSingulars);
  549.             }
  550.             foreach ($names as $name) {
  551.                 try {
  552.                     $reflectionMethod = new \ReflectionMethod($class$prefix.$name);
  553.                     if ($reflectionMethod->isStatic()) {
  554.                         continue;
  555.                     }
  556.                     // Parameter can be optional to allow things like: method(array $foo = null)
  557.                     if ($reflectionMethod->getNumberOfParameters() >= 1) {
  558.                         return [$reflectionMethod$prefix];
  559.                     }
  560.                 } catch (\ReflectionException $e) {
  561.                     // Try the next prefix if the method doesn't exist
  562.                 }
  563.             }
  564.         }
  565.         return null;
  566.     }
  567.     private function getPropertyName(string $methodName, array $reflectionProperties): ?string
  568.     {
  569.         $pattern implode('|'array_merge($this->accessorPrefixes$this->mutatorPrefixes));
  570.         if ('' !== $pattern && preg_match('/^('.$pattern.')(.+)$/i'$methodName$matches)) {
  571.             if (!\in_array($matches[1], $this->arrayMutatorPrefixes)) {
  572.                 return $matches[2];
  573.             }
  574.             foreach ($reflectionProperties as $reflectionProperty) {
  575.                 foreach ($this->inflector->singularize($reflectionProperty->name) as $name) {
  576.                     if (strtolower($name) === strtolower($matches[2])) {
  577.                         return $reflectionProperty->name;
  578.                     }
  579.                 }
  580.             }
  581.             return $matches[2];
  582.         }
  583.         return null;
  584.     }
  585.     /**
  586.      * Searches for add and remove methods.
  587.      *
  588.      * @param \ReflectionClass $reflClass The reflection class for the given object
  589.      * @param array            $singulars The singular form of the property name or null
  590.      *
  591.      * @return array An array containing the adder and remover when found and errors
  592.      */
  593.     private function findAdderAndRemover(\ReflectionClass $reflClass, array $singulars): array
  594.     {
  595.         if (!\is_array($this->arrayMutatorPrefixes) && !== \count($this->arrayMutatorPrefixes)) {
  596.             return [nullnull, []];
  597.         }
  598.         [$addPrefix$removePrefix] = $this->arrayMutatorPrefixes;
  599.         $errors = [];
  600.         foreach ($singulars as $singular) {
  601.             $addMethod $addPrefix.$singular;
  602.             $removeMethod $removePrefix.$singular;
  603.             [$addMethodFound$addMethodAccessibleErrors] = $this->isMethodAccessible($reflClass$addMethod1);
  604.             [$removeMethodFound$removeMethodAccessibleErrors] = $this->isMethodAccessible($reflClass$removeMethod1);
  605.             $errors[] = $addMethodAccessibleErrors;
  606.             $errors[] = $removeMethodAccessibleErrors;
  607.             if ($addMethodFound && $removeMethodFound) {
  608.                 return [$addMethod$removeMethod, []];
  609.             }
  610.             if ($addMethodFound && !$removeMethodFound) {
  611.                 $errors[] = [sprintf('The add method "%s" in class "%s" was found, but the corresponding remove method "%s" was not found'$addMethod$reflClass->getName(), $removeMethod)];
  612.             } elseif (!$addMethodFound && $removeMethodFound) {
  613.                 $errors[] = [sprintf('The remove method "%s" in class "%s" was found, but the corresponding add method "%s" was not found'$removeMethod$reflClass->getName(), $addMethod)];
  614.             }
  615.         }
  616.         return [nullnullarray_merge([], ...$errors)];
  617.     }
  618.     /**
  619.      * Returns whether a method is public and has the number of required parameters and errors.
  620.      */
  621.     private function isMethodAccessible(\ReflectionClass $classstring $methodNameint $parameters): array
  622.     {
  623.         $errors = [];
  624.         if ($class->hasMethod($methodName)) {
  625.             $method $class->getMethod($methodName);
  626.             if (\ReflectionMethod::IS_PUBLIC === $this->methodReflectionFlags && !$method->isPublic()) {
  627.                 $errors[] = sprintf('The method "%s" in class "%s" was found but does not have public access.'$methodName$class->getName());
  628.             } elseif ($method->getNumberOfRequiredParameters() > $parameters || $method->getNumberOfParameters() < $parameters) {
  629.                 $errors[] = sprintf('The method "%s" in class "%s" requires %d arguments, but should accept only %d.'$methodName$class->getName(), $method->getNumberOfRequiredParameters(), $parameters);
  630.             } else {
  631.                 return [true$errors];
  632.             }
  633.         }
  634.         return [false$errors];
  635.     }
  636.     /**
  637.      * Camelizes a given string.
  638.      */
  639.     private function camelize(string $string): string
  640.     {
  641.         return str_replace(' '''ucwords(str_replace('_'' '$string)));
  642.     }
  643.     /**
  644.      * Return allowed reflection method flags.
  645.      */
  646.     private function getMethodsFlags(int $accessFlags): int
  647.     {
  648.         $methodFlags 0;
  649.         if ($accessFlags self::ALLOW_PUBLIC) {
  650.             $methodFlags |= \ReflectionMethod::IS_PUBLIC;
  651.         }
  652.         if ($accessFlags self::ALLOW_PRIVATE) {
  653.             $methodFlags |= \ReflectionMethod::IS_PRIVATE;
  654.         }
  655.         if ($accessFlags self::ALLOW_PROTECTED) {
  656.             $methodFlags |= \ReflectionMethod::IS_PROTECTED;
  657.         }
  658.         return $methodFlags;
  659.     }
  660.     /**
  661.      * Return allowed reflection property flags.
  662.      */
  663.     private function getPropertyFlags(int $accessFlags): int
  664.     {
  665.         $propertyFlags 0;
  666.         if ($accessFlags self::ALLOW_PUBLIC) {
  667.             $propertyFlags |= \ReflectionProperty::IS_PUBLIC;
  668.         }
  669.         if ($accessFlags self::ALLOW_PRIVATE) {
  670.             $propertyFlags |= \ReflectionProperty::IS_PRIVATE;
  671.         }
  672.         if ($accessFlags self::ALLOW_PROTECTED) {
  673.             $propertyFlags |= \ReflectionProperty::IS_PROTECTED;
  674.         }
  675.         return $propertyFlags;
  676.     }
  677.     private function getReadVisiblityForProperty(\ReflectionProperty $reflectionProperty): string
  678.     {
  679.         if ($reflectionProperty->isPrivate()) {
  680.             return PropertyReadInfo::VISIBILITY_PRIVATE;
  681.         }
  682.         if ($reflectionProperty->isProtected()) {
  683.             return PropertyReadInfo::VISIBILITY_PROTECTED;
  684.         }
  685.         return PropertyReadInfo::VISIBILITY_PUBLIC;
  686.     }
  687.     private function getReadVisiblityForMethod(\ReflectionMethod $reflectionMethod): string
  688.     {
  689.         if ($reflectionMethod->isPrivate()) {
  690.             return PropertyReadInfo::VISIBILITY_PRIVATE;
  691.         }
  692.         if ($reflectionMethod->isProtected()) {
  693.             return PropertyReadInfo::VISIBILITY_PROTECTED;
  694.         }
  695.         return PropertyReadInfo::VISIBILITY_PUBLIC;
  696.     }
  697.     private function getWriteVisiblityForProperty(\ReflectionProperty $reflectionProperty): string
  698.     {
  699.         if ($reflectionProperty->isPrivate()) {
  700.             return PropertyWriteInfo::VISIBILITY_PRIVATE;
  701.         }
  702.         if ($reflectionProperty->isProtected()) {
  703.             return PropertyWriteInfo::VISIBILITY_PROTECTED;
  704.         }
  705.         return PropertyWriteInfo::VISIBILITY_PUBLIC;
  706.     }
  707.     private function getWriteVisiblityForMethod(\ReflectionMethod $reflectionMethod): string
  708.     {
  709.         if ($reflectionMethod->isPrivate()) {
  710.             return PropertyWriteInfo::VISIBILITY_PRIVATE;
  711.         }
  712.         if ($reflectionMethod->isProtected()) {
  713.             return PropertyWriteInfo::VISIBILITY_PROTECTED;
  714.         }
  715.         return PropertyWriteInfo::VISIBILITY_PUBLIC;
  716.     }
  717. }