classname = ltrim($class instanceof ReflectionClass ? $class->getName() : $class, '\\'); $this->cache = $cache; #if ( ! $this->cache || ! $this->cache->has($class) ) { $this->classReflection = $class instanceof ReflectionClass ? $class : new ReflectionClass($class); # } } public static function fromClass(ReflectionClass|string $class, ? CacheInterface $cache = null) : self { return new static($class, $cache); } public function getClassReflection() : ReflectionClass { return $this->classReflection; } public function reflectClass() : ReflectedClass { $parentClass = $this->classReflection->getParentClass(); return new ReflectedClass( name: $this->classReflection->getName(), parent: $parentClass ? static::fromClass($parentClass)->reflectClass() : false, methods: $this->reflectMethods(), properties: $this->reflectProperties(), attributes: AttributeReader::reflectAttributes($this->classReflection), interfaces: array_map(fn($interface) => static::fromClass($interface)->reflectClass(), array_keys($this->classReflection->getInterfaces())), traits: array_map(fn($trait) => static::fromClass($trait)->reflectClass(), array_keys($this->classReflection->getTraits())), ); } public function reflectProperties(int $filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE ) : array { $defaultValues = $this->classReflection->getDefaultProperties(); $list = []; foreach($this->classReflection->getProperties($filter) as $property) { $reflected = new ReflectedProperty($property->getName()); $reflected->attributes = AttributeReader::reflectAttributes($property); if ( $reflected->hasIgnoreAttribute() ) { continue; } # Default value can be 'null', so isset() it not suitable here if ( array_key_exists($reflected->name, $defaultValues) ) { $reflected->value = $defaultValues[ $reflected->name ]; } $reflected->typeFromReflection($property); $list[ $reflected->name ] = $reflected; } return array_merge($properties ?? [], $list); } public function reflectMethods(int $filter = ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED | ReflectionMethod::IS_PRIVATE | ReflectionMethod::IS_STATIC | ReflectionMethod::IS_FINAL ) : array { $list = []; foreach($this->classReflection->getMethods($filter) as $method) { # Skipping parent's methods, we'll retrieve them in its own reflection if ( $method->class !== $this->classname ) { continue; } $reflectedMethod = new ReflectedMethod( name: $method->getName(), classname: $method->class, type: $method->hasReturnType() ? $method->getReturnType() : false, isConstructor: $method->isConstructor(), isDestructor: $method->isDestructor(), isAbstract: $method->isAbstract(), attributes: AttributeReader::reflectAttributes($method), ); if ( $reflectedMethod->hasIgnoreAttribute() ) { continue; } foreach($method->getParameters() as $parameter) { $reflectedParameter = new ReflectedMethodProperty( name: $parameter->getName(), attributes: AttributeReader::reflectAttributes($parameter), ); if ( $reflectedParameter->hasIgnoreAttribute() ) { continue; } $reflectedParameter->position = $parameter->getPosition(); $reflectedParameter->typeFromReflection($parameter); $reflectedParameter->byReference = $parameter->isPassedByReference(); $reflectedParameter->optional = $parameter->isOptional(); $reflectedMethod->parameters[$reflectedParameter->name] = $reflectedParameter; } $list[$reflectedMethod->name] = $reflectedMethod; } return $list; } }