diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ff401c7..8a36a43 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -15,7 +15,7 @@ jobs: - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.3' + php-version: '8.4' coverage: pcov ini-values: pcov.directory=src - uses: actions/checkout@v2 diff --git a/src/ReflectionTypeFactory.php b/src/ReflectionTypeFactory.php index 8f0f652..51d0f3f 100644 --- a/src/ReflectionTypeFactory.php +++ b/src/ReflectionTypeFactory.php @@ -17,57 +17,17 @@ final class ReflectionTypeFactory */ private static array $alreadyCreated = []; - /** - * @codeCoverageIgnore - */ - private static function dummy(): string|false|null - { - return null; - } - - private static function createNullType(): ReflectionType - { - $refl = new ReflectionMethod(__CLASS__, 'dummy'); - return $refl->getReturnType()->getTypes()[2]; - } - - private static function createFalseType(): ReflectionType - { - $refl = new ReflectionMethod(__CLASS__, 'dummy'); - return $refl->getReturnType()->getTypes()[1]; - } - - private static function createTrueType(): ReflectionType - { - if (PHP_VERSION_ID < 80200) { - throw new LogicException('true typehint not supported in PHP < 8.2'); - } - $fakeClass = eval( - 'return new class { public function method(): string|true {} };' - ); - $refl = new ReflectionClass($fakeClass); - return $refl->getMethod('method')->getReturnType()->getTypes()[1]; - } - public static function createReflectionType(string $typehint): ReflectionType { if (strpos($typehint, ';') !== false || strpos($typehint, '/') !== false) { throw new RuntimeException('Are you trying to exploit this evil method?'); } if (!isset(self::$alreadyCreated[$typehint])) { - if ($typehint === 'null') { - self::$alreadyCreated[$typehint] = self::createNullType(); - } elseif ($typehint === 'false') { - self::$alreadyCreated[$typehint] = self::createFalseType(); - } elseif ($typehint === 'true') { - self::$alreadyCreated[$typehint] = self::createTrueType(); - } else { - $fakeClass = eval( - 'return new class { public function method(): ' . $typehint . '{} };' - ); - $refl = new ReflectionClass($fakeClass); - self::$alreadyCreated[$typehint] = $refl->getMethod('method')->getReturnType(); - } + $fakeClass = eval( + 'return new class { public function method(): ' . $typehint . '{} };' + ); + $refl = new ReflectionClass($fakeClass); + self::$alreadyCreated[$typehint] = $refl->getMethod('method')->getReturnType(); } return self::$alreadyCreated[$typehint]; } diff --git a/src/Utils/PropertyIterateUtil.php b/src/Utils/PropertyIterateUtil.php index ee7de8b..1e61a0e 100644 --- a/src/Utils/PropertyIterateUtil.php +++ b/src/Utils/PropertyIterateUtil.php @@ -21,7 +21,15 @@ public static function getReadProperties(ReflectionClass $class): array { $result = []; foreach ($class->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { - $result[$property->name] = $property->getType() ?? ReflectionTypeFactory::createReflectionType('mixed'); + if (PHP_VERSION_ID >= 80400 && $property->isVirtual()) { + $method = $property->getHook(\PropertyHookType::Get); + if ($method === null) { + continue; + } + $result[$property->name] = $method->getReturnType() ?? ReflectionTypeFactory::createReflectionType('mixed'); + } else { + $result[$property->name] = $property->getType() ?? ReflectionTypeFactory::createReflectionType('mixed'); + } } foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { if ($method->isStatic()) { @@ -48,7 +56,11 @@ public static function getWriteProperties(ReflectionClass $class): array if ($property->isReadOnly()) { continue; } - $result[$property->name] = $property->getType() ?? ReflectionTypeFactory::createReflectionType('mixed'); + $type = PHP_VERSION_ID >= 80400 ? $property->getSettableType() : $property->getType(); + if ((string) $type === 'never') { + continue; + } + $result[$property->name] = $type ?? ReflectionTypeFactory::createReflectionType('mixed'); } foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { if ($method->isStatic()) {