$this->autowire($className); } if (isset($this->definitions[$className])) { throw new Exception(sprintf('Class %s already defined', $className)); } $this->definitions[$className] = [ 'definition' => $definition, 'singleton' => $singleton, ]; return $this; } public function alias(string $alias, string $className): self { if (isset($this->aliases[$alias])) { throw new Exception(sprintf('Class %s already defined', $className)); } $this->aliases[$alias] = $className; return $this; } /** * @inheritDoc */ public function get(string $className): object { if (isset($this->aliases[$className])) { $className = $this->aliases[$className]; } if (!isset($this->definitions[$className])) { throw new ClassNotFoundException($className); } $definition = $this->definitions[$className]['definition']; if ($this->definitions[$className]['singleton']) { if (isset($this->instances[$className])) { return $this->instances[$className]; } $instance = $definition($this); if ($className !== LogContainer::class) { $logger = $this->get(LoggerInterface::class); $logger->add(sprintf('Created singleton instance of %s', $className)); } $this->instances[$className] = $instance; } else { $instance = $definition($this); } return $instance; } public function call(string $className, string $methodName, array $parameters = []): mixed { $params = $this->methodParams($className, $methodName, $parameters) + $parameters; return $this->get($className)->$methodName(...$params); } private function autowire(string $className): ?object { $reflection = new ReflectionClass($className); $reflectionMethod = $reflection->getConstructor(); if (!$reflectionMethod) { return new $className(); } return new $className(...$this->methodParams($className, $reflectionMethod->getName())); } private function methodParams(string $className, string $methodName, array $exceptParams = []): array { $reflectionMethod = new ReflectionMethod($className, $methodName); $params = []; foreach ($reflectionMethod->getParameters() as $parameter) { if (in_array($parameter->getName(), array_keys($exceptParams))) { continue; } $type = $parameter->getType(); if (!$type) { throw new Exception('Cannot autowire parameter without type'); } $params[] = $this->get($type->getName()); } return $params; } }