You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
4.0 KiB
135 lines
4.0 KiB
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* @author Robert Strutts
|
|
* @copyright Copyright (c) 2010-2026, Robert Strutts.
|
|
* @license MIT
|
|
*/
|
|
|
|
namespace IOcornerstone\Framework;
|
|
|
|
final class DI
|
|
{
|
|
|
|
protected $services = [];
|
|
|
|
// alias to register
|
|
public function set(...$args): void {
|
|
$this->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);
|
|
}
|
|
|
|
} |