Container::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cakasim\Payone\Sdk\Container;
6
7
use Cakasim\Payone\Sdk\Container\Binding\BindingInterface;
8
use Cakasim\Payone\Sdk\Container\Binding\CallableBinding;
9
use Cakasim\Payone\Sdk\Container\Binding\ClassBinding;
10
use Cakasim\Payone\Sdk\Container\Binding\InstanceBinding;
11
use Psr\Container\ContainerInterface;
12
13
/**
14
 * A PSR-11 container implementation that
15
 * provides simple yet powerful DI features.
16
 *
17
 * @author Fabian Böttcher <[email protected]>
18
 * @since 0.1.0
19
 */
20
final class Container implements ContainerInterface
21
{
22
    /**
23
     * @var BindingInterface[] Stores the entries of this container.
24
     */
25
    protected $entries = [];
26
27
    /**
28
     * Constructs the Container.
29
     *
30
     * @throws ContainerException If the container fails to bind itself.
31
     */
32
    public function __construct()
33
    {
34
        // Bind the container itself.
35
        $this->bindInstance(ContainerInterface::class, $this);
36
    }
37
38
    /**
39
     * @inheritDoc
40
     */
41
    public function has($id)
42
    {
43
        return isset($this->entries[$id]);
44
    }
45
46
    /**
47
     * Retrieves an entry from the container.
48
     *
49
     * @param string $id The entry ID.
50
     * @return object The container entry.
51
     *
52
     * @throws NotFountException If the entry ID does not exist.
53
     * @throws ContainerException If the entry could not be retrieved.
54
     */
55
    public function get($id)
56
    {
57
        if (!$this->has($id)) {
58
            throw new NotFountException("The entry for '{$id}' was not found.");
59
        }
60
61
        $entry = $this->entries[$id];
62
63
        if ($entry instanceof BindingInterface) {
0 ignored issues
show
introduced by
$entry is always a sub-type of Cakasim\Payone\Sdk\Conta...inding\BindingInterface.
Loading history...
64
            return $entry->resolve();
65
        }
66
67
        throw new ContainerException("Failed to get entry for '{$id}'.");
68
    }
69
70
    /**
71
     * Binds a concrete class to the provided ID.
72
     *
73
     * @param string $id The abstract type of the provided concrete.
74
     * @param string|null $concrete The concrete type or null if the provided ID should be used as concrete type.
75
     * @param bool $singleton True if the binding is a singleton.
76
     * @return $this
77
     *
78
     * @throws ContainerException If the binding fails.
79
     */
80
    public function bind(string $id, string $concrete = null, bool $singleton = false): self
81
    {
82
        $this->throwIfBindingToExistingEntry($id);
83
84
        if ($concrete === null) {
85
            $concrete = $id;
86
        }
87
88
        $this->entries[$id] = new ClassBinding($this, $id, $concrete, $singleton);
89
        return $this;
90
    }
91
92
    /**
93
     * Binds an instance to the provided ID.
94
     *
95
     * @param string $id The abstract type of the provided instance.
96
     * @param object $concrete The instance to bind to the ID.
97
     * @return $this
98
     *
99
     * @throws ContainerException If the binding fails.
100
     */
101
    public function bindInstance(string $id, $concrete): self
102
    {
103
        $this->throwIfBindingToExistingEntry($id);
104
105
        $this->entries[$id] = new InstanceBinding($id, $concrete);
106
        return $this;
107
    }
108
109
    /**
110
     * Binds a callable to the provided ID.
111
     * The callable must return an instance that is compatible
112
     * to the provided ID.
113
     *
114
     * @param string $id The abstract type of the callable's return value.
115
     * @param callable $concrete The callable which returns the actual binding.
116
     * @param bool $singleton True if the binding is a singleton.
117
     * @return $this
118
     *
119
     * @throws ContainerException If binding fails.
120
     */
121
    public function bindCallable(string $id, callable $concrete, bool $singleton = false): self
122
    {
123
        $this->throwIfBindingToExistingEntry($id);
124
125
        $this->entries[$id] = new CallableBinding($this, $id, $concrete, $singleton);
126
        return $this;
127
    }
128
129
    /**
130
     * Prevents binding to an already bound ID.
131
     *
132
     * @param string $id The identifier to check.
133
     *
134
     * @throws ContainerException If the provided ID is already bound.
135
     */
136
    protected function throwIfBindingToExistingEntry(string $id): void
137
    {
138
        if ($this->has($id)) {
139
            throw new ContainerException("Failed to bind to identifier '{$id}', the identifier is already bound.");
140
        }
141
    }
142
}
143