PocketMine-MP 5.39.1 git-1be3f83620f013523bb4d35535c6c0f842b54a6a
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
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()");
94 }
95 self::$inSetupClass = static::class;
96 try{
97 $this->setup();
98 }finally{
99 self::$inSetupClass = null;
100 }
101 }
102
109 abstract protected function setup() : void;
110
119 public static function preprocessMember(object $member) : object{
120 return $member;
121 }
122
131 final protected function registerValue(string $name, mixed $value) : mixed{
132 if(isset($this->simpleMembers[$name]) || isset($this->delayedMembers[$name])){
133 throw new \InvalidArgumentException("Cannot redeclare registry member \"$name\"");
134 }
135 $this->simpleMembers[$name] = $value;
136
137 return $value;
138 }
139
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\"");
154 }
155 Utils::validateCallableSignature(fn(string $name) : object => die(), $valueFactory);
156 $this->delayedMembers[$name] = $valueFactory;
157 }
158
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);
170 }
171 }
172
179 final public function getAllDeclarations() : array{
180 $this->setupWrapper();
181 $memberTypes = [];
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();
188 }
189
190 if($concrete === false){
191 $memberTypes[$name] = [];
192 }else{
193 $anonInterfaces = array_diff($reflect->getInterfaceNames(), $concrete->getInterfaceNames());
194 array_unshift($anonInterfaces, $concrete->getName());
195 $memberTypes[$name] = array_values($anonInterfaces);
196 }
197 }else{
198 $memberTypes[$name] = [$reflect->getName()];
199 }
200 }
201
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\"");
214 }
215 $memberTypes[$name][] = $type->getName();
216 }
217 }else{
218 throw new \LogicException("Unsupported delayed member type for \"$name\"");
219 }
220 }
221
222 return $memberTypes;
223 }
224}
registerDelayed(string $name, \Closure $valueFactory)
static preprocessMember(object $member)
registerValue(string $name, mixed $value)