Passed
Pull Request — master (#51)
by Arman
05:24 queued 02:50
created

Di::get()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 5
c 2
b 0
f 0
dl 0
loc 11
rs 10
cc 3
nc 3
nop 1
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.6.0
13
 */
14
15
namespace Quantum\Di;
16
17
use Quantum\Exceptions\DiException;
18
use ReflectionFunction;
19
use ReflectionClass;
20
use ReflectionMethod;
21
22
/**
23
 * Di Class
24
 * 
25
 * @package Quantum
26
 * @category Di
27
 */
28
class Di
29
{
30
31
    /**
32
     * @var array
33
     */
34
    private static $dependencies = [];
35
36
    /**
37
     * @var array
38
     */
39
    private static $container = [];
40
41
    /**
42
     * Loads dependency definitions
43
     */
44
    public static function loadDefinitions()
45
    {
46
        self::$dependencies = self::coreDependencies();
47
    }
48
49
    /**
50
     * Creates and injects dependencies.
51
     * @param callable $entry
52
     * @param array $additional
53
     * @return array
54
     * @throws \Quantum\Exceptions\DiException
55
     * @throws \ReflectionException
56
     */
57
    public static function autowire(callable $entry, array $additional = []): array
58
    {
59
        if (is_closure($entry)) {
60
            $reflection = new ReflectionFunction($entry);
61
        } else {
62
            $reflection = new ReflectionMethod(...$entry);
0 ignored issues
show
Bug introduced by
$entry is expanded, but the parameter $objectOrMethod of ReflectionMethod::__construct() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

62
            $reflection = new ReflectionMethod(/** @scrutinizer ignore-type */ ...$entry);
Loading history...
63
        }
64
65
        $params = [];
66
67
        foreach ($reflection->getParameters() as $param) {
68
            $type = $param->getType()->getName();
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

68
            $type = $param->getType()->/** @scrutinizer ignore-call */ getName();
Loading history...
69
70
            if (!$type || !self::instantiable($type)) {
71
                array_push($params, current($additional));
72
                next($additional);
73
                continue;
74
            }
75
76
            array_push($params, self::get($type));
77
        }
78
79
        return $params;
80
    }
81
82
    /**
83
     * Adds new dependecy
84
     * @param string $dependency
85
     */
86
    public static function add(string $dependency) {
87
        if(!in_array($dependency, self::$dependencies) && class_exists($dependency)) {
88
            array_push(self::$dependencies, $dependency);
89
        }
90
    }
91
92
    /**
93
     * Gets the dependency from the container
94
     * @param string $dependency
95
     * @return mixed
96
     * @throws \Quantum\Exceptions\DiException
97
     * @throws \ReflectionException
98
     */
99
    public static function get(string $dependency)
100
    {
101
        if (!in_array($dependency, self::$dependencies)) {
102
            throw DiException::dependencyNotDefined($dependency);
103
        }
104
105
        if (!isset(self::$container[$dependency])) {
106
            self::instantiate($dependency);
107
        }
108
109
        return self::$container[$dependency];
110
    }
111
112
    /**
113
     * Instantiates the dependency
114
     * @param string $dependency
115
     * @throws \Quantum\Exceptions\DiException|\ReflectionException
116
     */
117
    protected static function instantiate(string $dependency)
118
    {
119
        $class = new ReflectionClass($dependency);
120
121
        $constructor = $class->getConstructor();
122
123
        $params = [];
124
125
        if ($constructor) {
126
            foreach ($constructor->getParameters() as $param) {
127
                $type = $param->getType()->getName();
128
129
                if (!$type || !self::instantiable($type)) {
130
                    continue;
131
                }
132
133
                $params[] = self::get($type);
134
            }
135
        }
136
137
        self::$container[$dependency] = new $dependency(...$params);
138
    }
139
140
    /**
141
     * Checks if the class is instantiable
142
     * @param mixed $type
143
     * @return bool
144
     */
145
    protected static function instantiable($type): bool
146
    {
147
        return $type != 'Closure' && !is_callable($type) && class_exists($type);
148
    }
149
150
    /**
151
     * Gets the core dependencies 
152
     * @return array
153
     */
154
    private static function coreDependencies(): array
155
    {
156
        return [
157
            \Quantum\Http\Request::class,
158
            \Quantum\Http\Response::class,
159
            \Quantum\Loader\Loader::class,
160
            \Quantum\Factory\ViewFactory::class,
161
            \Quantum\Factory\ModelFactory::class,
162
            \Quantum\Factory\ServiceFactory::class,
163
            \Quantum\Libraries\Mailer\Mailer::class,
164
            \Quantum\Libraries\Storage\FileSystem::class,
165
        ];
166
    }
167
168
}
169