Completed
Push — master ( bee542...31e600 )
by James Ekow Abaka
01:58
created

Container::getSingletonInstance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 3
1
<?php
2
3
namespace ntentan\panie;
4
5
/**
6
 * Description of Container
7
 *
8
 * @author ekow
9
 */
10
class Container {
11
12
    private $bindings;
13
    private $singletons = [];
14
15
    public function __construct() {
16
        $this->bindings = new Bindings();
17
    }
18
19
    /**
20
     * 
21
     * @param string|\ReflectionClass $class
22
     * @return \ReflectionClass
23
     */
24
    public function getResolvedClassName($class) {
25
        $bound = null;
26
        if ($this->bindings->has($class)) {
27
            $bound = $this->bindings->get($class);
28
        } else if (is_string($class) && class_exists($class)) {
29
            $bound = ['class' => $class];
30
        }     
31
        return $bound;
32
    }
33
34
    public function bind($type) {
35
        return $this->bindings->setActiveKey($type);
36
    }
37
    
38
    public function unbind($type) {
39
        $this->bindings->remove($type);
40
    }
41
42
    public function singleton($type, $constructorArguments = []) {
43
        $resolvedClass = $this->getResolvedClassName($type)['class'];
44
        return $this->getSingletonInstance($type, $resolvedClass, $constructorArguments);
45
    }
46
    
47
    private function getSingletonInstance($type, $class,  $constructorArguments) {
48
        if (!isset($this->singletons[$type])) {
49
            $this->singletons[$type] = $this->getInstance($class, $constructorArguments);
50
        }
51
        return $this->singletons[$type];        
52
    }
53
    
54
    public function resolve($type, $constructorArguments = []) {
55
        if($type === null) {
56
            throw new exceptions\ResolutionException("Cannot resolve an empty type");
57
        } 
58
        $resolvedClass = $this->getResolvedClassName($type);
59
        if ($resolvedClass['class'] === null) {
60
            throw new exceptions\ResolutionException("Could not resolve dependency $type");
61
        }           
62
        if(isset($resolvedClass['singleton'])) {
63
            return $this->getSingletonInstance($type, $resolvedClass['class'], $constructorArguments);
64
        } else {
65
            return $this->getInstance($resolvedClass['class'], $constructorArguments);
66
        }
67
    }
68
69
    public function getInstance($className, $constructorArguments = []) {
70
        if(is_object($className)) {
71
            return $className;
72
        }
73
        $reflection = new \ReflectionClass($className);
74
        if ($reflection->isAbstract()) {
75
            throw new exceptions\ResolutionException(
76
            "Abstract class {$reflection->getName()} cannot be instantiated. "
77
            . "Please provide a binding to an implementation."
78
            );
79
        }
80
        $constructor = $reflection->getConstructor();
81
        $instanceParameters = [];
82
83
        if ($constructor != null) {
84
            $parameters = $constructor->getParameters();
85
            foreach ($parameters as $parameter) {
86
                $class = $parameter->getClass();
87
                $className = $class ? $class->getName() : null;
88
                if (isset($constructorArguments[$parameter->getName()])) {
89
                    $instanceParameters[] = $constructorArguments[$parameter->getName()];
90
                } else if($className == self::class){
91
                    $instanceParameters[] = $this;
92
                } else {                    
93
                    $instanceParameters[] = $className ? $this->resolve($className) : null;
94
                }
95
            }
96
        }
97
        return $reflection->newInstanceArgs($instanceParameters);
98
    }
99
100
}
101