Files
michaelschiemer/src/Framework/DI/MethodInvoker.php
Michael Schiemer cf0ad6e905 refactor: improve logging system and add deployment fixes
- Enhance logging handlers (Console, DockerJson, File, JsonFile, MultiFile)
- Improve exception and line formatters
- Update logger initialization and processor management
- Add Ansible playbooks for staging 502 error troubleshooting
- Update deployment documentation
- Fix serializer and queue components
- Update error kernel and queued log handler
2025-11-02 01:37:49 +01:00

135 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Framework\DI;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Reflection\ReflectionProvider;
use App\Framework\Reflection\WrappedReflectionMethod;
/**
* Führt Methoden auf beliebigen Klassen mit automatischer Dependency Injection aus
*/
final readonly class MethodInvoker
{
private ParameterResolver $parameterResolver;
public function __construct(
private Container $container,
private ReflectionProvider $reflectionProvider
) {
$this->parameterResolver = new ParameterResolver($container, $reflectionProvider);
}
/**
* Führt eine Methode auf einer Klasse aus und löst alle Parameter automatisch auf
*/
public function invoke(ClassName|string $className, string $methodName, array $overrides = []): mixed
{
if(is_string($className)) {
$className = ClassName::create($className);
}
$instance = $this->container->get($className->getFullyQualified());
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
{
$className = ClassName::fromObject($instance);
$reflection = $this->reflectionProvider->getClass($className);
if (! $reflection->hasMethod($methodName)) {
throw new \InvalidArgumentException(
"Method $methodName does not exist on class " . $instance::class
);
}
// Framework WrappedReflectionMethod verwenden
$method = $this->reflectionProvider->getMethod($className, $methodName);
$nativeMethod = $this->reflectionProvider->getNativeMethod($className, $methodName);
if (! $nativeMethod->isPublic()) {
throw new \InvalidArgumentException(
"Method $methodName on class " . $instance::class . " is not public"
);
}
$parameters = $this->resolveMethodParameters($className, $methodName, $overrides);
return $nativeMethod->invokeArgs($instance, $parameters);
}
/**
* Führt eine statische Methode aus
*/
public function invokeStatic(string $className, string $methodName, array $overrides = []): mixed
{
$classNameObj = ClassName::create($className);
$reflection = $this->reflectionProvider->getClass($classNameObj);
if (! $reflection->hasMethod($methodName)) {
throw new \InvalidArgumentException(
"Method '{$methodName}' does not exist on class '{$className}'"
);
}
// Framework WrappedReflectionMethod verwenden
$method = $this->reflectionProvider->getMethod($classNameObj, $methodName);
$nativeMethod = $this->reflectionProvider->getNativeMethod($classNameObj, $methodName);
if (! $nativeMethod->isStatic()) {
throw new \InvalidArgumentException(
"Method '{$methodName}' on class '{$className}' is not static"
);
}
$parameters = $this->resolveMethodParameters($classNameObj, $methodName, $overrides);
return $nativeMethod->invokeArgs(null, $parameters);
}
/**
* Erstellt eine neue Instanz mit automatischer Dependency Injection
* und optionalen Parameter-Overrides für den Constructor
*
* @template T of object
* @param class-string<T> $className
* @param array<string, mixed> $overrides Named constructor parameters
* @return T
*/
public function make(string $className, array $overrides = []): object
{
$classNameObj = ClassName::create($className);
$reflection = $this->reflectionProvider->getClass($classNameObj);
if (! $reflection->isInstantiable()) {
throw new \InvalidArgumentException(
"Class '{$className}' is not instantiable (interface, abstract class, or trait)"
);
}
// Check if class has constructor
if (! $reflection->hasMethod('__construct')) {
return $reflection->newInstance();
}
// Resolve constructor parameters with overrides
$parameters = $this->resolveMethodParameters($classNameObj, '__construct', $overrides);
return $reflection->newInstance(...$parameters);
}
/**
* Löst alle Parameter einer Methode auf
*/
private function resolveMethodParameters(ClassName $className, string $methodName, array $overrides): array
{
return $this->parameterResolver->resolveMethodParameters($className, $methodName, $overrides);
}
}