/** * Retrieve an instance of service from container * * @param string $key * @param array ...$args * @return mixed * @throws ContainerException * @throws Exception\RepositoryException */ public function get(string $key, ...$args) { // Check if service exists if (!$this->has($key)) { throw ContainerException::serviceNotFound(__METHOD__, $key); } // Check if its in Repository if ($this->repo->has($key)) { // Pull instance from repository return $this->repo->pull($key); } else { // Get new instance of service class $service = $this->services[$key]; return $service->createInstance($this, $args); } }
/** * Creates new instance of service * * @param Container $container * @param array $args * @return mixed * @throws ContainerException */ public function createInstance(Container $container, array $args) { // Prepare arguments for constructor $constructorArgs = []; foreach ($this->args as $arg) { $constructorArgs[] = $container->get($arg); } // Merge arguments foreach ($args as $arg) { array_push($constructorArgs, $arg); } // Construct $class = $this->className; /** @var $instance object */ $instance = new $class(...$constructorArgs); // Call setter methods foreach ($this->methods as $method => $di) { if (!is_callable([$instance, $method])) { // Setter method doesn't exist or isn't publicly callable throw ContainerException::injectMethodNotFound(__METHOD__, $class, $method, $di); } // Call method, inject dependency call_user_func_array([$instance, $method], [$container->get($di)]); } // Inject public properties $publicProperties = get_object_vars($instance); foreach ($this->properties as $property => $di) { // Check if property is public if (!in_array($property, $publicProperties)) { throw ContainerException::injectPropertyNotFound(__METHOD__, $class, $property, $di); } // Inject public property $instance->{$property} = $container->get($di); } // Return created instance return $instance; }