143 lines
5.2 KiB
PHP
143 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace Notes;
|
|
|
|
use Kash\HandleCacheTrait;
|
|
use Notes\Attribute\Ignore;
|
|
use Notes\Common\ReflectedClass;
|
|
use Notes\Common\ReflectedMethod;
|
|
use Notes\Common\ReflectedMethodProperty;
|
|
use Notes\Common\ReflectedProperty;
|
|
use Notes\Common\ReflectedPropertyType;
|
|
use Psr\SimpleCache\CacheInterface;
|
|
use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod, ReflectionUnionType, ReflectionNamedType, ReflectionParameter;
|
|
|
|
class ObjectReflection {
|
|
use HandleCacheTrait;
|
|
|
|
protected string $classname;
|
|
|
|
protected ReflectionClass $classReflection;
|
|
|
|
public function __construct(ReflectionClass|string $class, ? CacheInterface $cache = null) {
|
|
$this->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;
|
|
}
|
|
}
|