Skip to content

Instantly share code, notes, and snippets.

@izniburak
Created November 23, 2020 07:39
Show Gist options
  • Save izniburak/026dbe6251332842c51dafcb51e050df to your computer and use it in GitHub Desktop.
Save izniburak/026dbe6251332842c51dafcb51e050df to your computer and use it in GitHub Desktop.
Simple Dependency Injection (DI) Container for PHP
<?php
class Container
{
/**
* @var array
*/
protected $instances = [];
/**
* @param string $abstract
* @param string|Closure|null $concrete
*/
public function set(string $abstract, $concrete = null): void
{
if (is_null($concrete)) {
$concrete = $abstract;
}
$this->instances[$abstract] = $concrete;
}
/**
* @param string $abstract
* @param array $parameters
*
* @return mixed
* @throws Exception
*/
public function get(string $abstract, array $parameters = [])
{
// if we don't have it, just register it
if (!isset($this->instances[$abstract])) {
$this->set($abstract);
}
return $this->resolve($this->instances[$abstract], $parameters);
}
/**
* resolve single
*
* @param mixed $concrete
* @param array $parameters
*
* @return mixed
* @throws Exception
*/
public function resolve($concrete, array $parameters = [])
{
if ($concrete instanceof Closure) {
return $concrete($this, $parameters);
}
$reflector = new ReflectionClass($concrete);
// check if class is instantiable
if (!$reflector->isInstantiable()) {
throw new Exception("Class {$concrete} is not instantiable");
}
// get class constructor
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
// get new instance from class
return $reflector->newInstance();
}
// get constructor params
$parameters = $constructor->getParameters();
$dependencies = $this->getDependencies($parameters);
// get new instance with dependencies resolved
return $reflector->newInstanceArgs($dependencies);
}
/**
* get all dependencies resolved
*
* @param array $parameters
*
* @return array
* @throws Exception
*/
protected function getDependencies(array $parameters): array
{
$dependencies = [];
foreach ($parameters as $parameter) {
// get the type hinted class
$dependency = $parameter->getClass();
if (is_null($dependency)) {
// check if default value for a parameter is available
if (!$parameter->isDefaultValueAvailable()) {
throw new Exception("Can not resolve class dependency {$parameter->name}");
}
// get default value of parameter
$dependencies[] = $parameter->getDefaultValue();
} else {
// get dependency resolved
$dependencies[] = $this->get($dependency->name);
}
}
return $dependencies;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment