Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
49 / 49 |
|
100.00% |
8 / 8 |
CRAP | |
100.00% |
1 / 1 |
DiItem | |
100.00% |
49 / 49 |
|
100.00% |
8 / 8 |
32 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
11 | |||
hasSingletonValue | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setSingletonValue | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
5 | |||
getSingletonValue | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
class | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
value | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
factory | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
disposeImpl | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
8 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace PeServer\Core\DI; |
6 | |
7 | use TypeError; |
8 | use PeServer\Core\DisposerBase; |
9 | use PeServer\Core\IDisposable; |
10 | use PeServer\Core\Text; |
11 | use PeServer\Core\Throws\ArgumentException; |
12 | use PeServer\Core\Throws\InvalidOperationException; |
13 | use PeServer\Core\Throws\NotImplementedException; |
14 | use PeServer\Core\Throws\NotSupportedException; |
15 | use PeServer\Core\TypeUtility; |
16 | |
17 | /** |
18 | * DI登録値。 |
19 | * |
20 | * シングルトンデータは内包する。 |
21 | */ |
22 | class DiItem extends DisposerBase |
23 | { |
24 | #region define |
25 | |
26 | /** |
27 | * [ライフサイクル] 毎回作る。 |
28 | */ |
29 | public const LIFECYCLE_TRANSIENT = 0; |
30 | /** |
31 | * [ライフサイクル] シングルトン。 |
32 | */ |
33 | public const LIFECYCLE_SINGLETON = 1; |
34 | |
35 | /** |
36 | * [登録種別] 型。 |
37 | */ |
38 | public const TYPE_TYPE = 0; |
39 | /** |
40 | * [登録種別] 値。 |
41 | */ |
42 | public const TYPE_VALUE = 1; |
43 | /** |
44 | * [登録種別] 生成処理。 |
45 | */ |
46 | public const TYPE_FACTORY = 2; |
47 | |
48 | #endregion |
49 | |
50 | #region variable |
51 | |
52 | /** |
53 | * シングルトンデータを持つか。 |
54 | * |
55 | * @var bool |
56 | */ |
57 | private bool $hasSingletonValue = false; |
58 | /** |
59 | * シングルトンデータ。 |
60 | * |
61 | * @var mixed |
62 | */ |
63 | private mixed $singletonValue = null; |
64 | |
65 | #endregion |
66 | |
67 | /** |
68 | * 生成。 |
69 | * |
70 | * @param self::LIFECYCLE_* $lifecycle ライフサイクル。 |
71 | * @param self::TYPE_* $type 登録種別。 |
72 | * @param class-string|mixed|callable(IDiContainer, DiItem[]):mixed $data 登録データ。 |
73 | * @param bool $nonDisposal IDisposable 対象にするか。 |
74 | */ |
75 | public function __construct( |
76 | public int $lifecycle, |
77 | public int $type, |
78 | public mixed $data, |
79 | public bool $nonDisposal = false |
80 | ) { |
81 | if ($lifecycle !== self::LIFECYCLE_TRANSIENT && $lifecycle !== self::LIFECYCLE_SINGLETON) { //@phpstan-ignore-line self::LIFECYCLE_* |
82 | throw new ArgumentException('$lifecycle: ' . $lifecycle); |
83 | } |
84 | |
85 | switch ($type) { |
86 | case self::TYPE_TYPE: |
87 | if (!is_string($data)) { |
88 | throw new TypeError('$data: ' . TypeUtility::getType($data)); |
89 | } |
90 | if (Text::isNullOrWhiteSpace($data)) { |
91 | throw new ArgumentException('$data: empty'); |
92 | } |
93 | break; |
94 | |
95 | case self::TYPE_VALUE: |
96 | if ($lifecycle != self::LIFECYCLE_SINGLETON) { |
97 | throw new ArgumentException('$lifecycle: self::LIFECYCLE_SINGLETON'); |
98 | } |
99 | $this->hasSingletonValue = true; |
100 | $this->singletonValue = $data; |
101 | break; |
102 | |
103 | case self::TYPE_FACTORY: |
104 | if (!is_callable($data)) { |
105 | throw new TypeError('$data: ' . TypeUtility::getType($data)); |
106 | } |
107 | break; |
108 | |
109 | default: |
110 | throw new NotSupportedException('$type: ' . $type); |
111 | } |
112 | } |
113 | |
114 | #region function |
115 | |
116 | /** |
117 | * シングルトンデータを保持しているか。 |
118 | * |
119 | * @return bool |
120 | */ |
121 | public function hasSingletonValue(): bool |
122 | { |
123 | if ($this->lifecycle != self::LIFECYCLE_SINGLETON) { |
124 | return false; |
125 | } |
126 | |
127 | return $this->hasSingletonValue; |
128 | } |
129 | |
130 | |
131 | /** |
132 | * シングルトンデータを設定。 |
133 | * |
134 | * DIコンテナ側で処理する想定。 |
135 | * |
136 | * @param mixed $value |
137 | * @throws NotSupportedException |
138 | * @throws InvalidOperationException |
139 | */ |
140 | public function setSingletonValue(mixed $value): void |
141 | { |
142 | if ($this->lifecycle != self::LIFECYCLE_SINGLETON) { |
143 | throw new NotSupportedException(); |
144 | } |
145 | if ($this->hasSingletonValue) { |
146 | throw new InvalidOperationException(); |
147 | } |
148 | |
149 | if ($this->type === self::TYPE_TYPE) { |
150 | if (!is_a($value, (string)$this->data)) { |
151 | throw new TypeError(TypeUtility::getType($value) . ' - ' . $this->data); |
152 | } |
153 | } |
154 | |
155 | $this->singletonValue = $value; |
156 | $this->hasSingletonValue = true; |
157 | } |
158 | |
159 | /** |
160 | * シングルトンデータを設定。 |
161 | * |
162 | * @return mixed |
163 | * @throws NotSupportedException |
164 | * @throws InvalidOperationException |
165 | */ |
166 | public function getSingletonValue(): mixed |
167 | { |
168 | if ($this->lifecycle != self::LIFECYCLE_SINGLETON) { |
169 | throw new NotSupportedException(); |
170 | } |
171 | if (!$this->hasSingletonValue) { |
172 | throw new InvalidOperationException(); |
173 | } |
174 | |
175 | return $this->singletonValue; |
176 | } |
177 | |
178 | /** |
179 | * 型: クラスとして生成。 |
180 | * |
181 | * @template T |
182 | * @param class-string $className |
183 | * @phpstan-param class-string<T> $className |
184 | * @param self::LIFECYCLE_* $lifecycle |
185 | * @return self |
186 | */ |
187 | public static function class(string $className, int $lifecycle = self::LIFECYCLE_TRANSIENT): self |
188 | { |
189 | return new self($lifecycle, self::TYPE_TYPE, $className); |
190 | } |
191 | |
192 | /** |
193 | * 値として生成。 |
194 | * |
195 | * @template T |
196 | * @param mixed $data |
197 | * @phpstan-param T $data |
198 | * @return self |
199 | */ |
200 | public static function value(mixed $data): self |
201 | { |
202 | return new self(self::LIFECYCLE_SINGLETON, self::TYPE_VALUE, $data); |
203 | } |
204 | |
205 | /** |
206 | * 生成処理として生成。 |
207 | * |
208 | * @template T |
209 | * @param callable $factory |
210 | * @phpstan-param callable(IDiContainer,DiItem[]):T $factory |
211 | * @param self::LIFECYCLE_* $lifecycle |
212 | * @return self |
213 | */ |
214 | public static function factory(callable $factory, int $lifecycle = self::LIFECYCLE_TRANSIENT): self |
215 | { |
216 | return new self($lifecycle, self::TYPE_FACTORY, $factory); |
217 | } |
218 | |
219 | #endregion |
220 | |
221 | #region DisposerBase |
222 | |
223 | protected function disposeImpl(): void |
224 | { |
225 | if ($this->nonDisposal) { |
226 | return; |
227 | } |
228 | |
229 | /** @var IDisposable|null */ |
230 | $disposer = null; |
231 | |
232 | if ($this->type === DiItem::TYPE_VALUE) { |
233 | if ($this->data instanceof IDisposable) { |
234 | $disposer = $this->data; |
235 | } |
236 | } |
237 | if ($this->lifecycle === DiItem::LIFECYCLE_SINGLETON) { |
238 | if ($this->hasSingletonValue()) { |
239 | $value = $this->getSingletonValue(); |
240 | if ($value instanceof IDisposable) { |
241 | $disposer = $value; |
242 | } |
243 | } |
244 | } |
245 | |
246 | if ($disposer !== null) { |
247 | $disposer->dispose(); |
248 | } |
249 | } |
250 | |
251 | #endregion |
252 | } |