chore: complete update
This commit is contained in:
127
src/Framework/DI/MethodInvoker.php
Normal file
127
src/Framework/DI/MethodInvoker.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\DI;
|
||||
|
||||
use App\Framework\Reflection\ReflectionProvider;
|
||||
use ReflectionMethod;
|
||||
use ReflectionNamedType;
|
||||
|
||||
/**
|
||||
* Führt Methoden auf beliebigen Klassen mit automatischer Dependency Injection aus
|
||||
*/
|
||||
final readonly class MethodInvoker
|
||||
{
|
||||
public function __construct(
|
||||
private Container $container,
|
||||
private ReflectionProvider $reflectionCache
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Führt eine Methode auf einer Klasse aus und löst alle Parameter automatisch auf
|
||||
*/
|
||||
public function invoke(string $className, string $methodName, array $overrides = []): mixed
|
||||
{
|
||||
$instance = $this->container->get($className);
|
||||
return $this->invokeOn($instance, $methodName, $overrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* Führt eine Methode auf einer bereits existierenden Instanz aus
|
||||
*/
|
||||
public function invokeOn(object $instance, string $methodName, array $overrides = []): mixed
|
||||
{
|
||||
$reflection = $this->reflectionCache->getClass($instance::class);
|
||||
|
||||
if (!$reflection->hasMethod($methodName)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Method $methodName does not exist on class $instance::class"
|
||||
);
|
||||
}
|
||||
|
||||
$method = $this->reflectionCache->getMethod($instance::class, $methodName);
|
||||
|
||||
if (!$method->isPublic()) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Method $methodName on class $instance::class is not public"
|
||||
);
|
||||
}
|
||||
|
||||
$parameters = $this->resolveMethodParameters($method, $overrides);
|
||||
|
||||
return $method->invokeArgs($instance, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Führt eine statische Methode aus
|
||||
*/
|
||||
public function invokeStatic(string $className, string $methodName, array $overrides = []): mixed
|
||||
{
|
||||
$reflection = $this->reflectionCache->getClass($className);
|
||||
|
||||
if (!$reflection->hasMethod($methodName)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Method '{$methodName}' does not exist on class '{$className}'"
|
||||
);
|
||||
}
|
||||
|
||||
$method = $this->reflectionCache->getMethod($className, $methodName);
|
||||
|
||||
if (!$method->isStatic()) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Method '{$methodName}' on class '{$className}' is not static"
|
||||
);
|
||||
}
|
||||
|
||||
$parameters = $this->resolveMethodParameters($method, $overrides);
|
||||
|
||||
return $method->invokeArgs(null, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Löst alle Parameter einer Methode auf
|
||||
*/
|
||||
private function resolveMethodParameters(ReflectionMethod $method, array $overrides): array
|
||||
{
|
||||
$parameters = [];
|
||||
|
||||
foreach ($method->getParameters() as $param) {
|
||||
$paramName = $param->getName();
|
||||
|
||||
// Override-Werte haben Priorität
|
||||
if (array_key_exists($paramName, $overrides)) {
|
||||
$parameters[] = $overrides[$paramName];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Type-based injection
|
||||
$type = $param->getType();
|
||||
|
||||
if ($type instanceof ReflectionNamedType && !$type->isBuiltin()) {
|
||||
$typeName = $type->getName();
|
||||
|
||||
if ($this->container->has($typeName)) {
|
||||
$parameters[] = $this->container->get($typeName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Default-Werte verwenden
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
$parameters[] = $param->getDefaultValue();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Nullable Parameter
|
||||
if ($type && $type->allowsNull()) {
|
||||
$parameters[] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(
|
||||
"Cannot resolve parameter '{$paramName}' for method '{$method->getName()}' on class '{$method->getDeclaringClass()->getName()}'"
|
||||
);
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user