54 private ThreadSafeArray $fallbackLookup;
59 private ThreadSafeArray $psr4Lookup;
61 public function __construct(){
62 $this->fallbackLookup =
new ThreadSafeArray();
63 $this->psr4Lookup =
new ThreadSafeArray();
66 protected function normalizePath(
string $path) :
string{
67 $parts = explode(
"://", $path, 2);
68 if(count($parts) === 2){
69 return $parts[0] .
"://" . str_replace(
'/', DIRECTORY_SEPARATOR, $parts[1]);
71 return str_replace(
'/', DIRECTORY_SEPARATOR, $parts[0]);
74 public function addPath(
string $namespacePrefix,
string $path,
bool $prepend =
false) :
void{
75 $path = $this->normalizePath($path);
76 if($namespacePrefix ===
'' || $namespacePrefix ===
'\\'){
77 $this->fallbackLookup->synchronized(
function() use ($path, $prepend) :
void{
81 $namespacePrefix = trim($namespacePrefix,
'\\') .
'\\';
82 $this->psr4Lookup->synchronized(
function() use ($namespacePrefix, $path, $prepend) :
void{
83 $list = $this->psr4Lookup[$namespacePrefix] ??
null;
85 $list = $this->psr4Lookup[$namespacePrefix] =
new ThreadSafeArray();
99 foreach($entries as $removedEntry){
100 $list[] = $removedEntry;
115 while(($entry = $list->shift()) !==
null){
121 public function register(
bool $prepend =
false) : bool{
122 return spl_autoload_register(function(string $name) : void{
123 $this->loadClass($name);
131 $path = $this->findClass($name);
134 if(!class_exists($name,
false) && !interface_exists($name,
false) && !trait_exists($name,
false)){
138 if(method_exists($name,
"onClassLoaded") && (
new \ReflectionClass($name))->getMethod(
"onClassLoaded")->isStatic()){
139 $name::onClassLoaded();
152 $baseName = str_replace(
"\\", DIRECTORY_SEPARATOR, $name);
154 foreach($this->fallbackLookup as $path){
155 $filename = $path . DIRECTORY_SEPARATOR . $baseName .
".php";
156 if(file_exists($filename)){
162 $logicalPathPsr4 = $baseName .
".php";
164 return $this->psr4Lookup->synchronized(
function() use ($name, $logicalPathPsr4) : ?
string{
166 while(
false !== $lastPos = strrpos($subPath,
'\\')){
167 $subPath = substr($subPath, 0, $lastPos);
168 $search = $subPath .
'\\';
169 $lookup = $this->psr4Lookup[$search] ??
null;
170 if($lookup !==
null){
171 $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
172 foreach($lookup as $dir){
173 if(file_exists($file = $dir . $pathEnd)){