57 private array $simpleMembers = [];
63 private array $delayedMembers = [];
65 private static ?
string $inSetupClass =
null;
67 final public function __construct(){
97 private function setupWrapper() : void{
98 if(self::$inSetupClass !== null){
99 throw new \LogicException(
"Registry source class " . self::$inSetupClass .
" tried to reference a member of registry " . $this->getTargetClassName() .
" without using registerDelayed()");
101 self::$inSetupClass = static::class;
105 self::$inSetupClass =
null;
115 abstract protected function setup() : void;
138 if(isset($this->simpleMembers[$name]) || isset($this->delayedMembers[$name])){
139 throw new \InvalidArgumentException(
"Cannot redeclare registry member \"$name\"");
141 $this->simpleMembers[$name] = $value;
157 final protected function registerDelayed(
string $name, \Closure $valueFactory) : void{
158 if(isset($this->simpleMembers[$name]) || isset($this->delayedMembers[$name])){
159 throw new \InvalidArgumentException(
"Cannot redeclare registry member \"$name\"");
161 Utils::validateCallableSignature(fn(
string $name) :
object => die(), $valueFactory);
162 $this->delayedMembers[$name] = $valueFactory;
171 final public function getAllValues() : \
Generator{
172 $this->setupWrapper();
173 yield from $this->simpleMembers;
174 foreach(Utils::stringifyKeys($this->delayedMembers) as $name => $callback){
175 yield $name => $callback($name);
185 final public function getAllDeclarations() : array{
186 $this->setupWrapper();
188 foreach(Utils::stringifyKeys($this->simpleMembers) as $name => $value){
189 $reflect = new \ReflectionClass($value);
190 $concrete = $reflect;
191 if($reflect->isAnonymous()){
192 while($concrete !==
false && $concrete->isAnonymous()){
193 $concrete = $concrete->getParentClass();
196 if($concrete ===
false){
197 $memberTypes[$name] = [];
199 $anonInterfaces = array_diff($reflect->getInterfaceNames(), $concrete->getInterfaceNames());
200 array_unshift($anonInterfaces, $concrete->getName());
201 $memberTypes[$name] = array_values($anonInterfaces);
204 $memberTypes[$name] = [$reflect->getName()];
208 foreach(Utils::stringifyKeys($this->delayedMembers) as $name => $callback){
209 $return = (new \ReflectionFunction($callback))->getReturnType();
210 if($return ===
null){
211 \GlobalLogger::get()->warning(
"Delayed registry member " . $this->getTargetClassName() .
"::" . $name .
" doesn't have a return type, using \"object\"");
212 $memberTypes[$name] = [];
213 }elseif($return instanceof \ReflectionNamedType){
214 $memberTypes[$name] = [$return->getName()];
215 }elseif($return instanceof \ReflectionIntersectionType){
216 $memberTypes[$name] = [];
217 foreach($return->getTypes() as $type){
218 if(!$type instanceof \ReflectionNamedType){
219 throw new \InvalidArgumentException(
"Unsupported nested type in intersection type for \"$name\"");
221 $memberTypes[$name][] = $type->getName();
224 throw new \LogicException(
"Unsupported delayed member type for \"$name\"");