register(...$args); } // alias to get_service public function get(...$args) { return $this->get_service(...$args); } public function register(string $serviceName, callable $callable): void { $this->services[$serviceName] = $callable; } public function has(string $serviceName): bool { return (array_key_exists($serviceName, $this->services)); } public function exists(string $serviceName) { // an Alias to has return $this->has($serviceName); } /* Note args may be an object or an array maybe more...! * This will Call/Execute the service */ public function get_service( string $serviceName, $args = [], ...$more ) { if ($this->has($serviceName) ) { $entry = $this->services[$serviceName]; if (is_callable($entry)) { return $entry($args, $more); } $serviceName = $entry; } return $this->resolve($serviceName); // Try to Auto-Wire } public function get_auto(string $serviceName) { if ($this->has($serviceName) ) { return $this->services[$serviceName]($this); } return $this->resolve($serviceName); // Try to Auto-Wire } public function __set(string $serviceName, callable $callable): void { $this->register($serviceName, $callable); } public function __get(string $serviceName) { return $this->get_service($serviceName); } public function list_services_as_array(): array { return array_keys($this->services); } public function list_services_as_string(): string { return implode(',', array_keys($this->services)); } // Reflection API Autowiring FROM-> https://www.youtube.com/watch?v=78Vpg97rQwE&list=PLr3d3QYzkw2xabQRUpcZ_IBk9W50M9pe-&index=72 public function resolve(string $serviceName) { try { $reflection_class = new \ReflectionClass($serviceName); } catch (\ReflectionException $e) { // if (! is_live()) { // var_dump($e->getTrace()); // echo $e->getMessage(); // exit; // } else { throw new \Exception("Failed to resolve resource: {$serviceName}!"); // } } if (! $reflection_class->isInstantiable()) { throw new \Exception("The Service class: {$serviceName} is not instantiable."); } $constructor = $reflection_class->getConstructor(); if (! $constructor) { return new $serviceName; } $parameters = $constructor->getParameters(); if (! $parameters) { return new $serviceName; } $dependencies = array_map( function(\ReflectionParameter $param) use ($serviceName) { $name = $param->getName(); $type = $param->getType(); if (! $type) { throw new \Exception("Failed to resolve class: {$serviceName} because param {$name} is missing a type hint."); } if ($type instanceof \ReflectionUnionType) { throw new \Exception("Failed to resolve class: {$serviceName} because of union type for param {$name}."); } if ($type instanceof \ReflectionNamedType && ! $type->isBuiltin()) { return $this->get_auto($type->getName()); } throw new \Exception("Failed to resolve class {$serviceName} because of invalid param {$param}."); }, $parameters ); return $reflection_class->newInstanceArgs($dependencies); } }