- var_dump: documentation ( source)
- class_exists: documentation ( source)
- method_exists: documentation ( source)
<?php
# basic container
class Container
{
private $raw; // callbacks
private $values; // objects
private $locked;
public function __construct(array $config = [])
{
foreach($config as $id => $callback){
$this->set($id, $callback);
}
}
public function set(string $id, callable $callback): void
{
if(isset($this->locked[$id])){
throw new LockedIdException();
}
$this->raw[$id] = $callback;
}
public function get(string $id)
{
if(!isset($this->raw[$id])){
throw new UnknownIdException();
}
if(isset($this->values[$id])){
return $this->values[$id];
}
$cb = $this->raw[$id];
$val = $this->values[$id] = $cb($this);
$this->locked[$id] = true;
return $val;
}
public function has(string $id): bool
{
return isset($this->values[$id]);
}
}
class Resolver
{
public function __construct(Container $container, WireRule ...$rules)
{
$this->c = $container;
$this->rules = $rules;
}
public function get(string $class)
{
if(!$this->c->has($class)){
$this->c->set($class, $this->resolve($class));
}
return $this->c->get($class);
}
public function resolve(string $class): callable
{
if(!class_exists($class)){
throw new UnknownIdException();
}
if(!method_exists($class, '__construct')){
return function(Container $c) use ($class){ return new $class; };
}
$constructor = new \ReflectionMethod($class, '__construct');
if(count($params = $constructor->getParameters()) === 0){
return function(Container $c) use ($class){ return new $class; };
}
foreach($params as $param){
$args[] = $param->hasType() ? $this->getArgument($param->getType()->__toString()) : null;
}
return function(Container $c) use ($class, $args){
return new $class(...$args);
};
}
public function getArgument(string $type)
{
foreach($this->rules as $rule){
if($rule->match($type)){
$type = $rule->getWiredClass($type);
}
}
return $type ? $this->get($type) : null;
}
}
class Foo { public function __construct(Bar $bar){ $this->bar = $bar; }}
class Bar { public function __construct(Baz $baz){ $this->baz = $baz; }}
class Baz {}
$c = new Resolver(new Container);
var_dump($c->get(Foo::class));