diff --git a/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/CookieAndSessionMisuse.php b/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/CookieAndSessionMisuse.php index 1d49d9343a282..d03253bd166dc 100644 --- a/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/CookieAndSessionMisuse.php +++ b/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/CookieAndSessionMisuse.php @@ -8,11 +8,16 @@ namespace Magento\CodeMessDetector\Rule\Design; +use Magento\Framework\Session\SessionManagerInterface; +use Magento\Framework\Stdlib\Cookie\CookieReaderInterface; use PDepend\Source\AST\ASTClass; use PHPMD\AbstractNode; use PHPMD\AbstractRule; use PHPMD\Node\ClassNode; use PHPMD\Rule\ClassAware; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; /** * Session and Cookies must be used only in HTML Presentation layer. @@ -105,7 +110,7 @@ private function isControllerPlugin(\ReflectionClass $class): bool foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { if (preg_match('/^(after|around|before).+/i', $method->getName())) { try { - $argument = $method->getParameters()[0]->getClass(); + $argument = $this->getParameterClass($method->getParameters()[0]); } catch (\Throwable $exception) { //Non-existing class (autogenerated perhaps) or doesn't have an argument. continue; @@ -134,7 +139,7 @@ private function isBlockPlugin(\ReflectionClass $class): bool foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { if (preg_match('/^(after|around|before).+/i', $method->getName())) { try { - $argument = $method->getParameters()[0]->getClass(); + $argument = $this->getParameterClass($method->getParameters()[0]); } catch (\Throwable $exception) { //Non-existing class (autogenerated perhaps) or doesn't have an argument. continue; @@ -164,14 +169,16 @@ private function doesUseRestrictedClasses(\ReflectionClass $class): bool if ($constructor) { foreach ($constructor->getParameters() as $argument) { try { - if ($class = $argument->getClass()) { - if ($class->isSubclassOf(\Magento\Framework\Session\SessionManagerInterface::class) - || $class->getName() === \Magento\Framework\Session\SessionManagerInterface::class - || $class->isSubclassOf(\Magento\Framework\Stdlib\Cookie\CookieReaderInterface::class) - || $class->getName() === \Magento\Framework\Stdlib\Cookie\CookieReaderInterface::class - ) { - return true; - } + $class = $this->getParameterClass($argument); + if ($class === null) { + continue; + } + if ($class->isSubclassOf(SessionManagerInterface::class) + || $class->getName() === SessionManagerInterface::class + || $class->isSubclassOf(CookieReaderInterface::class) + || $class->getName() === CookieReaderInterface::class + ) { + return true; } } catch (\ReflectionException $exception) { //Failed to load the argument's class information @@ -183,6 +190,22 @@ private function doesUseRestrictedClasses(\ReflectionClass $class): bool return false; } + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } + /** * @inheritdoc * diff --git a/dev/tests/static/framework/Magento/TestFramework/Integrity/Library/Injectable.php b/dev/tests/static/framework/Magento/TestFramework/Integrity/Library/Injectable.php index 524a4f7be3616..3a47f4547d4cb 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Integrity/Library/Injectable.php +++ b/dev/tests/static/framework/Magento/TestFramework/Integrity/Library/Injectable.php @@ -8,6 +8,9 @@ use Laminas\Code\Reflection\ClassReflection; use Laminas\Code\Reflection\FileReflection; use Laminas\Code\Reflection\ParameterReflection; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; /** * Provide dependencies for the file @@ -39,7 +42,7 @@ public function getDependencies(FileReflection $fileReflection) foreach ($method->getParameters() as $parameter) { try { /** @var ParameterReflection $parameter */ - $dependency = $parameter->getClass(); + $dependency = $this->getParameterClass($parameter); if ($dependency instanceof ClassReflection) { $this->dependencies[] = $dependency->getName(); } @@ -56,4 +59,20 @@ public function getDependencies(FileReflection $fileReflection) return $this->dependencies; } + + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } } diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php index 29ac58f39d89b..b5e61ed2ece8e 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php @@ -6,6 +6,9 @@ namespace Magento\Test\Integrity; use Magento\Framework\App\Utility\Files; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; /** * Tests @api annotated code integrity @@ -277,7 +280,7 @@ private function checkParameters($class, \ReflectionMethod $method, array $nonPu && !$parameter->getType()->isBuiltin() && !$this->isGenerated($parameter->getType()->getName()) ) { - $parameterClass = $parameter->getClass(); + $parameterClass = $this->getParameterClass($parameter); /* * We don't want to check integrity of @api coverage of classes * that belong to different vendors, because it is too complicated. @@ -286,7 +289,7 @@ private function checkParameters($class, \ReflectionMethod $method, array $nonPu * we don't want to fail test, because Zend is considered public by default, * and we don't care if Zend classes are @api-annotated */ - if (!$parameterClass->isInternal() + if ($parameterClass && !$parameterClass->isInternal() && $this->areClassesFromSameVendor($parameterClass->getName(), $class) && !$this->isPublished($parameterClass) ) { @@ -296,4 +299,20 @@ private function checkParameters($class, \ReflectionMethod $method, array $nonPu } return $nonPublishedClasses; } + + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } } diff --git a/lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php b/lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php index f29474f476b45..b0fe493ab0eaa 100644 --- a/lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php +++ b/lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php @@ -6,6 +6,9 @@ namespace Magento\Framework\Code\Generator; use Laminas\Code\Generator\ValueGenerator; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; /** * Abstract entity @@ -323,29 +326,46 @@ protected function _getNullDefaultValue() private function extractParameterType( \ReflectionParameter $parameter ): ?string { + if (!$parameter->hasType()) { + return null; + } + /** @var string|null $typeName */ $typeName = null; - if ($parameter->hasType()) { - if ($parameter->isArray()) { - $typeName = 'array'; - } elseif ($parameter->getClass()) { - $typeName = $this->_getFullyQualifiedClassName( - $parameter->getClass()->getName() - ); - } elseif ($parameter->isCallable()) { - $typeName = 'callable'; - } else { - $typeName = $parameter->getType()->getName(); - } - if ($parameter->allowsNull()) { - $typeName = '?' .$typeName; - } + if ($parameter->isArray()) { + $typeName = 'array'; + } elseif ($parameterClass = $this->getParameterClass($parameter)) { + $typeName = $this->_getFullyQualifiedClassName($parameterClass->getName()); + } elseif ($parameter->isCallable()) { + $typeName = 'callable'; + } else { + $typeName = $parameter->getType()->getName(); + } + + if ($parameter->allowsNull()) { + $typeName = '?' . $typeName; } return $typeName; } + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } + /** * Extract parameter default value * diff --git a/lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php b/lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php index c9a8cce706af4..3396093c78bc4 100644 --- a/lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php +++ b/lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php @@ -5,6 +5,10 @@ */ namespace Magento\Framework\Code\Reader; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; + /** * The class arguments reader */ @@ -98,11 +102,13 @@ public function getConstructorArguments(\ReflectionClass $class, $groupByPositio */ private function processType(\ReflectionClass $class, \Laminas\Code\Reflection\ParameterReflection $parameter) { - if ($parameter->getClass()) { - return NamespaceResolver::NS_SEPARATOR . $parameter->getClass()->getName(); + $parameterClass = $this->getParameterClass($parameter); + + if ($parameterClass) { + return NamespaceResolver::NS_SEPARATOR . $parameterClass->getName(); } - $type = $parameter->detectType(); + $type = $parameter->detectType(); if ($type === 'null') { return null; @@ -121,6 +127,22 @@ private function processType(\ReflectionClass $class, \Laminas\Code\Reflection\P return $type; } + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } + /** * Get arguments of parent __construct call * diff --git a/lib/internal/Magento/Framework/Code/Reader/ClassReader.php b/lib/internal/Magento/Framework/Code/Reader/ClassReader.php index 2aad3b83390bf..d796cd8978cd0 100644 --- a/lib/internal/Magento/Framework/Code/Reader/ClassReader.php +++ b/lib/internal/Magento/Framework/Code/Reader/ClassReader.php @@ -5,6 +5,10 @@ */ namespace Magento\Framework\Code\Reader; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; + /** * Class ClassReader */ @@ -17,32 +21,34 @@ class ClassReader implements ClassReaderInterface * * @param string $className * @return array|null - * @throws \ReflectionException + * @throws ReflectionException */ public function getConstructor($className) { - $class = new \ReflectionClass($className); + $class = new ReflectionClass($className); $result = null; $constructor = $class->getConstructor(); if ($constructor) { $result = []; - /** @var $parameter \ReflectionParameter */ + /** @var $parameter ReflectionParameter */ foreach ($constructor->getParameters() as $parameter) { try { + $parameterClass = $this->getParameterClass($parameter); + $result[] = [ $parameter->getName(), - $parameter->getClass() !== null ? $parameter->getClass()->getName() : null, + $parameterClass ? $parameterClass->getName() : null, !$parameter->isOptional() && !$parameter->isDefaultValueAvailable(), $this->getReflectionParameterDefaultValue($parameter), $parameter->isVariadic(), ]; - } catch (\ReflectionException $e) { + } catch (ReflectionException $e) { $message = sprintf( 'Impossible to process constructor argument %s of %s class', $parameter->__toString(), $className ); - throw new \ReflectionException($message, 0, $e); + throw new ReflectionException($message, 0, $e); } } } @@ -50,13 +56,29 @@ public function getConstructor($className) return $result; } + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } + /** * Get reflection parameter default value * - * @param \ReflectionParameter $parameter + * @param ReflectionParameter $parameter * @return array|mixed|null */ - private function getReflectionParameterDefaultValue(\ReflectionParameter $parameter) + private function getReflectionParameterDefaultValue(ReflectionParameter $parameter) { if ($parameter->isVariadic()) { return []; diff --git a/lib/internal/Magento/Framework/Code/Reader/SourceArgumentsReader.php b/lib/internal/Magento/Framework/Code/Reader/SourceArgumentsReader.php index 840cc2a3e943c..16cb47e2fa119 100644 --- a/lib/internal/Magento/Framework/Code/Reader/SourceArgumentsReader.php +++ b/lib/internal/Magento/Framework/Code/Reader/SourceArgumentsReader.php @@ -5,6 +5,10 @@ */ namespace Magento\Framework\Code\Reader; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; + class SourceArgumentsReader { /** @@ -61,7 +65,7 @@ public function getConstructorArgumentTypes( $typeName = 'array'; } else { try { - $paramClass = $param->getClass(); + $paramClass = $this->getParameterClass($param); if ($paramClass) { $typeName = '\\' .$paramClass->getName(); } @@ -81,6 +85,22 @@ public function getConstructorArgumentTypes( return $types; } + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } + /** * Perform namespace resolution if required and return fully qualified name. * diff --git a/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php b/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php index b67af21878c3d..5eab8dd62ebd3 100644 --- a/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php +++ b/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php @@ -8,6 +8,9 @@ use Magento\Framework\Code\Reader\ArgumentsReader; use Magento\Framework\Exception\ValidatorException; use Magento\Framework\Phrase; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; /** * @SuppressWarnings(PHPMD.NPathComplexity) @@ -162,16 +165,32 @@ protected function validateMethodsParameters(array $pluginParameters, array $ori /** * Get parameters type * - * @param \ReflectionParameter $parameter + * @param ReflectionParameter $parameter * * @return string */ - protected function getParametersType(\ReflectionParameter $parameter) + protected function getParametersType(ReflectionParameter $parameter) { - $parameterClass = $parameter->getClass(); + $parameterClass = $this->getParameterClass($parameter); return $parameterClass ? '\\' . $parameterClass->getName() : ($parameter->isArray() ? 'array' : null); } + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } + /** * Get intercepted method name * diff --git a/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ObjectManager.php b/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ObjectManager.php index 69156225e9c39..adf6e81c10c5f 100644 --- a/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ObjectManager.php +++ b/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ObjectManager.php @@ -6,6 +6,9 @@ namespace Magento\Framework\TestFramework\Unit\Helper; use PHPUnit\Framework\MockObject\MockObject; +use ReflectionClass; +use ReflectionException; +use ReflectionParameter; /** * Helper class for basic object retrieving, such as blocks, models etc... @@ -222,7 +225,8 @@ function ($className, $arguments) { } elseif ($parameter->allowsNull()) { $args[] = null; } else { - $mock = $this->_getMockWithoutConstructorCall($parameter->getClass()->getName()); + $parameterClass = $this->getParameterClass($parameter); + $mock = $this->_getMockWithoutConstructorCall($parameterClass->getName()); $args[] = $mock; } } @@ -237,6 +241,22 @@ function ($className, $arguments) { return new $className(...array_values($this->getConstructArguments($className, $arguments))); } + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } + /** * Retrieve associative array of arguments that used for new object instance creation * @@ -268,8 +288,8 @@ public function getConstructArguments($className, array $arguments = []) $object = null; try { - if ($parameter->getClass()) { - $argClassName = $parameter->getClass()->getName(); + if ($parameterClass = $this->getParameterClass($parameter)) { + $argClassName = $parameterClass->getName(); } $object = $this->_getMockObject($argClassName, $arguments); } catch (\ReflectionException $e) { diff --git a/setup/src/Zend/Mvc/Controller/LazyControllerAbstractFactory.php b/setup/src/Zend/Mvc/Controller/LazyControllerAbstractFactory.php index 57697cd9cd9bf..b015aaf401115 100644 --- a/setup/src/Zend/Mvc/Controller/LazyControllerAbstractFactory.php +++ b/setup/src/Zend/Mvc/Controller/LazyControllerAbstractFactory.php @@ -26,6 +26,7 @@ use Laminas\Stdlib\DispatchableInterface; use Laminas\Validator\ValidatorPluginManager; use ReflectionClass; +use ReflectionException; use ReflectionParameter; /** @@ -168,11 +169,12 @@ private function resolveParameter(ContainerInterface $container, $requestedName) return []; } - if (! $parameter->getClass()) { + $parameterClass = $this->getParameterClass($parameter); + if (!$parameterClass) { return null; } - $type = $parameter->getClass()->getName(); + $type = $parameterClass->getName(); $type = isset($this->aliases[$type]) ? $this->aliases[$type] : $type; if (! $container->has($type)) { @@ -188,6 +190,22 @@ private function resolveParameter(ContainerInterface $container, $requestedName) }; } + /** + * Get class by reflection parameter + * + * @param ReflectionParameter $reflectionParameter + * @return ReflectionClass|null + * @throws ReflectionException + */ + private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass + { + $parameterType = $reflectionParameter->getType(); + + return $parameterType && !$parameterType->isBuiltin() + ? new ReflectionClass($parameterType->getName()) + : null; + } + /** * Determine if we can create a service with name *