yiisoft/yii

Call to undefined method ReflectionUnionType::getName() in CConsoleCommand.php

aztechowski opened this issue · 4 comments

What steps will reproduce the problem?

Create an ConsoleCommand with an action having union type parameter, e.g.

public function actionDoSomething( array|string|int|null $unionParameter = null ): int {

Call from shell that action

What is the expected result?

Actions runs w/o error. The method run of CConsoleCommand should detect ReflectionUnionType and call getTypes.

What do you get instead?

The logic doesn't recognize ReflectionUnionType and use getType() method available in other Reflection classes, but not in ReflectionUnionType, which has onlky getTypes() method. This leads to an exception
Call to undefined method ReflectionUnionType::getName() in W:\00.www\sites\dobryslownik.trunk\vendor\yiisoft\yii\framework\cons
ole\CConsoleCommand.php:133

Additional info

Q A
Yii version latest
PHP version 8.2
Operating system Windows/Linux

I've build an workaround (written in PHP 8.2 style), which can be adopted here.
Instead of

if(version_compare(PHP_VERSION,'8.0','>=')) {
    $isArray=$param->getType() && $param->getType()->getName()==='array';
} else {
  $isArray = $param->isArray();
}

I'm using following code

    //repleced by
    $isArray = $this->isParameterAnArray($param);
  
    //check whenever given parameter is an array, or not. Supports complex types (intersections, unions) from PHP 8 and above
    private function isParameterAnArray($param): bool
    {
        if (PHP_VERSION_ID < 80000) {
            return $param->isArray();
        }
        foreach ($this->getAllTypes($param) as $complexType) {
            if ($complexType && $complexType->getName() === 'array') {
                return true;
            }
        }
        return false;
    }

    //Get all available types. In case an Intersection (PHP >= 8.1) or Union Type (PHP > 8.0) is used, then give all defined types 
    private function getAllTypes($param): array
    {
        if ((PHP_VERSION_ID >= 81000) && $param->getType() instanceof ReflectionIntersectionType) {
            return $param->getType()->getTypes();
        }
        if ($param->getType() instanceof ReflectionUnionType) {
            return $param->getType()->getTypes();
        }
        return [$param->getType()];
    }

Similar to #4516

Yep, it can be combined and solved together.

Fixed by #4519