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

<?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);
}
}