PocketMine-MP 5.39.3 git-21ae710729750cd637333d673bbbbbc598fc659e
Loading...
Searching...
No Matches
RegistrySource.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\utils;
25
26use function array_diff;
27use function array_unshift;
28use function array_values;
29
51abstract class RegistrySource{
52
57 private array $simpleMembers = [];
58
63 private array $delayedMembers = [];
64
65 private static ?string $inSetupClass = null;
66
67 final public function __construct(){
68 //NOOP
69 }
70
75 abstract public function getTargetClassName() : string;
76
84 public function getTargetClassDocComment() : array{
85 return [];
86 }
87
92 public function cloneResults() : bool{ return false; }
93
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()");
100 }
101 self::$inSetupClass = static::class;
102 try{
103 $this->setup();
104 }finally{
105 self::$inSetupClass = null;
106 }
107 }
108
115 abstract protected function setup() : void;
116
125 public static function preprocessMember(object $member) : object{
126 return $member;
127 }
128
137 final protected function registerValue(string $name, mixed $value) : mixed{
138 if(isset($this->simpleMembers[$name]) || isset($this->delayedMembers[$name])){
139 throw new \InvalidArgumentException("Cannot redeclare registry member \"$name\"");
140 }
141 $this->simpleMembers[$name] = $value;
142
143 return $value;
144 }
145
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\"");
160 }
161 Utils::validateCallableSignature(fn(string $name) : object => die(), $valueFactory);
162 $this->delayedMembers[$name] = $valueFactory;
163 }
164
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);
176 }
177 }
178
185 final public function getAllDeclarations() : array{
186 $this->setupWrapper();
187 $memberTypes = [];
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();
194 }
195
196 if($concrete === false){
197 $memberTypes[$name] = [];
198 }else{
199 $anonInterfaces = array_diff($reflect->getInterfaceNames(), $concrete->getInterfaceNames());
200 array_unshift($anonInterfaces, $concrete->getName());
201 $memberTypes[$name] = array_values($anonInterfaces);
202 }
203 }else{
204 $memberTypes[$name] = [$reflect->getName()];
205 }
206 }
207
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\"");
220 }
221 $memberTypes[$name][] = $type->getName();
222 }
223 }else{
224 throw new \LogicException("Unsupported delayed member type for \"$name\"");
225 }
226 }
227
228 return $memberTypes;
229 }
230}
registerDelayed(string $name, \Closure $valueFactory)
static preprocessMember(object $member)
registerValue(string $name, mixed $value)