Update reflection container to support manual injecting

This commit is contained in:
ArabCoders
2025-01-22 11:31:18 +03:00
parent de379559bf
commit 6369103b09
2 changed files with 58 additions and 6 deletions

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Libs\Attributes\DI;
use Attribute;
#[Attribute(Attribute::TARGET_PARAMETER)]
readonly class Inject
{
/**
* Dynamically override dependency resolve. This is useful when you want to
* resolve a dependency to a specific class which is not the same as the
* type-hinted interface.
*
* For example, you have an interface `LoggerInterface` and you have two
* classes that implement this interface: `FileLogger` and `DatabaseLogger`.
* And you want to resolve the `LoggerInterface` to `FileLogger` when it is
* type-hinted in a constructor. You can use this attribute to achieve that.
* By doing the following:
*
* <code>
* class Example
* {
* public function __invoke(#[Inject(FileLogger::class)] private LoggerInterface $logger) {}
* }
* </code>
*
* @param string $name
*/
public function __construct(public string $name)
{
}
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Libs\Extends;
use App\Libs\Attributes\DI\Inject;
use League\Container\Argument\{ArgumentInterface,
ArgumentResolverInterface,
DefaultValueArgument,
@@ -200,6 +201,24 @@ class ReflectionContainer implements ArgumentResolverInterface, ContainerInterfa
continue;
}
$attributes = $param->getAttributes(Inject::class);
if (count($attributes) > 0) {
$injector = $attributes[0]->newInstance();
assert($injector instanceof Inject);
if (array_key_exists($injector->name, $args)) {
$arguments[] = new LiteralArgument($args[$injector->name]);
continue;
}
if ($param->isDefaultValueAvailable()) {
$arguments[] = new DefaultValueArgument($injector->name, $param->getDefaultValue());
continue;
}
$arguments[] = new ResolvableArgument($injector->name);
continue;
}
$type = $param->getType();
if ($type instanceof ReflectionNamedType) {
@@ -225,12 +244,10 @@ class ReflectionContainer implements ArgumentResolverInterface, ContainerInterfa
continue;
}
throw new NotFoundException(
r("Unable to resolve a value for parameter '{param}' in the function/method '{method}'.", [
'param' => $name,
'method' => $method->getName(),
])
);
throw new NotFoundException(r("Unable to resolve a value for parameter '{param}' in '{method}'.", [
'param' => $name,
'method' => $method->getName(),
]));
}
return $this->resolveArguments($arguments);