57 private array $simpleMembers = [];
63 private array $delayedMembers = [];
65 private static ?
string $inSetupClass =
null;
67 final public function __construct(){
91 private function setupWrapper() : void{
92 if(self::$inSetupClass !== null){
93 throw new \LogicException(
"Registry source class " . self::$inSetupClass .
" tried to reference a member of registry " . $this->getTargetClassName() .
" without using registerDelayed()");
95 self::$inSetupClass = static::class;
99 self::$inSetupClass =
null;
109 abstract protected function setup() : void;
132 if(isset($this->simpleMembers[$name]) || isset($this->delayedMembers[$name])){
133 throw new \InvalidArgumentException(
"Cannot redeclare registry member \"$name\"");
135 $this->simpleMembers[$name] = $value;
151 final protected function registerDelayed(
string $name, \Closure $valueFactory) : void{
152 if(isset($this->simpleMembers[$name]) || isset($this->delayedMembers[$name])){
153 throw new \InvalidArgumentException(
"Cannot redeclare registry member \"$name\"");
155 Utils::validateCallableSignature(fn(
string $name) :
object => die(), $valueFactory);
156 $this->delayedMembers[$name] = $valueFactory;
165 final public function getAllValues() : \
Generator{
166 $this->setupWrapper();
167 yield from $this->simpleMembers;
168 foreach(Utils::stringifyKeys($this->delayedMembers) as $name => $callback){
169 yield $name => $callback($name);
179 final public function getAllDeclarations() : array{
180 $this->setupWrapper();
182 foreach(Utils::stringifyKeys($this->simpleMembers) as $name => $value){
183 $reflect = new \ReflectionClass($value);
184 $concrete = $reflect;
185 if($reflect->isAnonymous()){
186 while($concrete !==
false && $concrete->isAnonymous()){
187 $concrete = $concrete->getParentClass();
190 if($concrete ===
false){
191 $memberTypes[$name] = [];
193 $anonInterfaces = array_diff($reflect->getInterfaceNames(), $concrete->getInterfaceNames());
194 array_unshift($anonInterfaces, $concrete->getName());
195 $memberTypes[$name] = array_values($anonInterfaces);
198 $memberTypes[$name] = [$reflect->getName()];
202 foreach(Utils::stringifyKeys($this->delayedMembers) as $name => $callback){
203 $return = (new \ReflectionFunction($callback))->getReturnType();
204 if($return ===
null){
205 \GlobalLogger::get()->warning(
"Delayed registry member " . $this->getTargetClassName() .
"::" . $name .
" doesn't have a return type, using \"object\"");
206 $memberTypes[$name] = [];
207 }elseif($return instanceof \ReflectionNamedType){
208 $memberTypes[$name] = [$return->getName()];
209 }elseif($return instanceof \ReflectionIntersectionType){
210 $memberTypes[$name] = [];
211 foreach($return->getTypes() as $type){
212 if(!$type instanceof \ReflectionNamedType){
213 throw new \InvalidArgumentException(
"Unsupported nested type in intersection type for \"$name\"");
215 $memberTypes[$name][] = $type->getName();
218 throw new \LogicException(
"Unsupported delayed member type for \"$name\"");