Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
100.00% |
239 / 239 |
|
96.70% |
176 / 182 |
|
47.22% |
85 / 180 |
|
83.33% |
20 / 24 |
CRAP | |
0.00% |
0 / 1 |
| Container | |
100.00% |
239 / 239 |
|
96.70% |
176 / 182 |
|
47.22% |
85 / 180 |
|
100.00% |
24 / 24 |
1336.31 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
8 / 8 |
|
100.00% |
4 / 4 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| scope | |
100.00% |
8 / 8 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| reset | |
100.00% |
7 / 7 |
|
100.00% |
5 / 5 |
|
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
| has | |
100.00% |
6 / 6 |
|
100.00% |
7 / 7 |
|
37.50% |
3 / 8 |
|
100.00% |
1 / 1 |
7.91 | |||
| entries | |
100.00% |
11 / 11 |
|
100.00% |
6 / 6 |
|
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
4 | |||
| entry | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| get | |
100.00% |
32 / 32 |
|
96.00% |
24 / 25 |
|
47.62% |
10 / 21 |
|
100.00% |
1 / 1 |
28.39 | |||
| instance | |
100.00% |
6 / 6 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| add | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| addEntry | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| tag | |
100.00% |
15 / 15 |
|
100.00% |
7 / 7 |
|
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
4 | |||
| new | |
100.00% |
11 / 11 |
|
86.67% |
13 / 15 |
|
21.05% |
4 / 19 |
|
100.00% |
1 / 1 |
23.71 | |||
| resolveEntry | |
100.00% |
19 / 19 |
|
100.00% |
15 / 15 |
|
24.14% |
7 / 29 |
|
100.00% |
1 / 1 |
35.94 | |||
| resolutionContainers | |
100.00% |
5 / 5 |
|
77.78% |
7 / 9 |
|
75.00% |
3 / 4 |
|
100.00% |
1 / 1 |
4.25 | |||
| materialize | |
100.00% |
40 / 40 |
|
95.45% |
21 / 22 |
|
66.67% |
10 / 15 |
|
100.00% |
1 / 1 |
13.70 | |||
| checkedArgs | |
100.00% |
5 / 5 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| applyCalls | |
100.00% |
9 / 9 |
|
100.00% |
6 / 6 |
|
75.00% |
3 / 4 |
|
100.00% |
1 / 1 |
3.14 | |||
| resetScope | |
100.00% |
12 / 12 |
|
100.00% |
10 / 10 |
|
18.52% |
5 / 27 |
|
100.00% |
1 / 1 |
12.66 | |||
| resetIfNeeded | |
100.00% |
9 / 9 |
|
100.00% |
8 / 8 |
|
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
4 | |||
| trackAndReturn | |
100.00% |
3 / 3 |
|
100.00% |
5 / 5 |
|
75.00% |
3 / 4 |
|
100.00% |
1 / 1 |
3.14 | |||
| findEntry | |
100.00% |
7 / 7 |
|
100.00% |
10 / 10 |
|
71.43% |
5 / 7 |
|
100.00% |
1 / 1 |
5.58 | |||
| root | |
100.00% |
4 / 4 |
|
100.00% |
4 / 4 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| assertMutable | |
100.00% |
2 / 2 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| seal | |
100.00% |
6 / 6 |
|
100.00% |
9 / 9 |
|
16.67% |
2 / 12 |
|
100.00% |
1 / 1 |
13.26 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Celema\Container; |
| 6 | |
| 7 | use Celema\Container\Exception\ContainerException; |
| 8 | use Celema\Container\Exception\NotFoundException; |
| 9 | use Celema\Container\Exception\ResetFailed; |
| 10 | use Celema\Wire\CallableResolver; |
| 11 | use Celema\Wire\Creator; |
| 12 | use Celema\Wire\Exception\WireException; |
| 13 | use Closure; |
| 14 | use Override; |
| 15 | use Psr\Container\ContainerExceptionInterface; |
| 16 | use Psr\Container\ContainerInterface as PsrContainer; |
| 17 | use Throwable; |
| 18 | |
| 19 | /** @psalm-api */ |
| 20 | class Container implements PsrContainer |
| 21 | { |
| 22 | protected Creator $creator; |
| 23 | protected readonly ?PsrContainer $wrappedContainer; |
| 24 | protected bool $sealed = false; |
| 25 | |
| 26 | /** @var array<string, Entry> */ |
| 27 | protected array $entries = []; |
| 28 | |
| 29 | /** @var array<string, mixed> */ |
| 30 | protected array $instances = []; |
| 31 | |
| 32 | /** @var array<non-empty-string, self> */ |
| 33 | protected array $tags = []; |
| 34 | |
| 35 | /** @var array<int, Resettable> */ |
| 36 | protected array $usedResettables = []; |
| 37 | |
| 38 | /** The root tag whose registrations a scope's tag container lists and resolves. */ |
| 39 | protected ?Container $inherits = null; |
| 40 | |
| 41 | public function __construct( |
| 42 | public readonly bool $autowire = true, |
| 43 | ?PsrContainer $container = null, |
| 44 | protected readonly string $tag = '', |
| 45 | protected readonly ?Container $parent = null, |
| 46 | protected readonly bool $isScope = false, |
| 47 | ) { |
| 48 | if ($container) { |
| 49 | $this->wrappedContainer = $container; |
| 50 | $this->add(PsrContainer::class, $container); |
| 51 | $this->add($container::class, $container); |
| 52 | } else { |
| 53 | $this->wrappedContainer = null; |
| 54 | $this->add(PsrContainer::class, $this); |
| 55 | } |
| 56 | $this->add(Container::class, $this); |
| 57 | $this->creator = new Creator($this); |
| 58 | } |
| 59 | |
| 60 | public function scope(): Container |
| 61 | { |
| 62 | $root = $this->root(); |
| 63 | |
| 64 | if (!$root->sealed) { |
| 65 | $root->seal(); |
| 66 | } |
| 67 | |
| 68 | return new self( |
| 69 | autowire: $root->autowire, |
| 70 | parent: $root, |
| 71 | isScope: true, |
| 72 | ); |
| 73 | } |
| 74 | |
| 75 | public function reset(): void |
| 76 | { |
| 77 | if (!$this->isScope) { |
| 78 | return; |
| 79 | } |
| 80 | |
| 81 | $resetIds = []; |
| 82 | $failures = []; |
| 83 | $this->resetScope($resetIds, $failures); |
| 84 | |
| 85 | if ($failures !== []) { |
| 86 | throw new ResetFailed($failures); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | #[Override] |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 100 | |
| 101 | /** @return list<string> */ |
| 102 | public function entries(bool $includeContainer = false): array |
| 103 | { |
| 104 | $inherited = $this->inherits?->entries(true) ?? []; |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 107 | : array_values(array_unique([...array_keys($this->entries), ...$inherited])); |
| 108 | |
| 109 | if ($includeContainer) { |
| 110 | return $keys; |
| 111 | } |
| 112 | |
| 113 | return array_values(array_filter( |
| 114 | $keys, |
| 115 | static fn(string $item): bool => $item !== PsrContainer::class |
| 116 | && !is_subclass_of($item, PsrContainer::class), |
| 117 | )); |
| 118 | } |
| 119 | |
| 120 | public function entry(string $id): Entry |
| 121 | { |
| 122 | return ( |
| 123 | $this->entries[$id] |
| 124 | ?? $this->inherits?->entries[$id] |
| 125 | ?? throw new NotFoundException('Unresolvable entry - id: ' . $id) |
| 126 | ); |
| 127 | } |
| 128 | |
| 129 | #[Override] |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 134 | return $this->trackAndReturn($this->instances[$id]); |
| 135 | } |
| 136 | |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 140 | return $this->trackAndReturn( |
| 141 | $this->resolveEntry( |
| 142 | entryOwner: $resolved[0], |
| 143 | entry: $resolved[1], |
| 144 | id: $id, |
| 145 | requester: $this, |
| 146 | ), |
| 147 | ); |
| 148 | } |
| 149 | |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 151 | // Ids that were not tagged belong to the container that owns the |
| 152 | // tag. Resolving them there keeps their lifetime caches and the |
| 153 | // overrides of an enclosing scope. |
| 154 | return $this->parent->get($id); |
| 155 | } |
| 156 | |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 160 | return $this->trackAndReturn($wrappedContainer->get($id)); |
| 161 | } |
| 162 | |
| 163 | // Autowiring: $id does not exists as an entry in the container |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 166 | } |
| 167 | } catch (WireException $e) { |
| 168 | throw new NotFoundException( |
| 169 | 'Unresolvable id: ' . $id . ' - Details: ' . $e->getMessage(), |
| 170 | previous: $e, |
| 171 | ); |
| 172 | } catch (ContainerExceptionInterface $e) { |
| 173 | throw $e; |
| 174 | } catch (Throwable $e) { |
| 175 | throw new ContainerException( |
| 176 | 'Unresolvable id: ' . $id . ' - ' . $e->getMessage(), |
| 177 | previous: $e, |
| 178 | ); |
| 179 | } |
| 180 | |
| 181 | throw new NotFoundException('Unresolvable id: ' . $id); |
| 182 | } |
| 183 | |
| 184 | /** |
| 185 | * @template T of object |
| 186 | * @param class-string<T> $class |
| 187 | * @return T |
| 188 | */ |
| 189 | public function instance(string $class): object |
| 190 | { |
| 191 | /** @var mixed $value */ |
| 192 | $value = $this->get($class); |
| 193 | |
| 194 | if (!$value instanceof $class) { |
| 195 | throw new ContainerException( |
| 196 | "Entry '{$class}' resolves to " . get_debug_type($value) . ', not an instance of it', |
| 197 | ); |
| 198 | } |
| 199 | |
| 200 | return $value; |
| 201 | } |
| 202 | |
| 203 | /** |
| 204 | * @param non-empty-string $id |
| 205 | */ |
| 206 | public function add( |
| 207 | string $id, |
| 208 | mixed $value = null, |
| 209 | ): Entry { |
| 210 | $this->assertMutable(); |
| 211 | $entry = new Entry($id, $value ?? $id); |
| 212 | $this->entries[$id] = $entry; |
| 213 | unset($this->instances[$id]); |
| 214 | |
| 215 | return $entry; |
| 216 | } |
| 217 | |
| 218 | public function addEntry( |
| 219 | Entry $entry, |
| 220 | ): Entry { |
| 221 | $this->assertMutable(); |
| 222 | $this->entries[$entry->id] = $entry; |
| 223 | unset($this->instances[$entry->id]); |
| 224 | |
| 225 | return $entry; |
| 226 | } |
| 227 | |
| 228 | /** @param non-empty-string $tag */ |
| 229 | public function tag(string $tag): Container |
| 230 | { |
| 231 | if (isset($this->tags[$tag])) { |
| 232 | return $this->tags[$tag]; |
| 233 | } |
| 234 | |
| 235 | if ($this->sealed) { |
| 236 | // Reading a tag that was never registered is not a structural change. |
| 237 | // The empty view is not stored, so the sealed container stays as it is. |
| 238 | $view = new self(autowire: $this->autowire, tag: $tag, parent: $this); |
| 239 | $view->seal(); |
| 240 | |
| 241 | return $view; |
| 242 | } |
| 243 | |
| 244 | $tagContainer = new self( |
| 245 | autowire: $this->autowire, |
| 246 | tag: $tag, |
| 247 | parent: $this, |
| 248 | isScope: $this->isScope, |
| 249 | ); |
| 250 | |
| 251 | // A scope's tag lists the root tag's registrations and adds its own, |
| 252 | // while untagged ids resolve through the scope. |
| 253 | if ($this->isScope) { |
| 254 | $tagContainer->inherits = $this->root()->tags[$tag] ?? null; |
| 255 | } |
| 256 | |
| 257 | return $this->tags[$tag] = $tagContainer; |
| 258 | } |
| 259 | |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 265 | /** @var mixed $value */ |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 270 | return $this->new($value, ...$args); |
| 271 | } |
| 272 | |
| 273 | if (class_exists($value)) { |
| 274 | // Psalm cannot know the constructor of a class named at runtime. |
| 275 | /** @psalm-suppress MixedMethodCall */ |
| 276 | return new $value(...$args); |
| 277 | } |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | if (class_exists($id)) { |
| 282 | // Psalm cannot know the constructor of a class named at runtime. |
| 283 | /** @psalm-suppress MixedMethodCall */ |
| 284 | return new $id(...$args); |
| 285 | } |
| 286 | |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 289 | |
| 290 | protected function resolveEntry( |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 297 | return $entry->definition(); |
| 298 | } |
| 299 | |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 301 | throw new ContainerException( |
| 302 | "Scoped entry '{$id}' cannot be resolved by the root container after scope() was called, " |
| 303 | . 'as every scope would share that instance. It is most likely a dependency of a shared ' |
| 304 | . 'entry: make that entry scoped or transient, or resolve the entry from a scope.', |
| 305 | ); |
| 306 | } |
| 307 | |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 316 | } |
| 317 | |
| 318 | // materialize() intentionally returns mixed because container entries may resolve to any value type. |
| 319 | /** @psalm-suppress MixedAssignment */ |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 327 | } |
| 328 | |
| 329 | /** |
| 330 | * @return array{0: null|Container, 1: Container} |
| 331 | */ |
| 332 | protected function resolutionContainers( |
| 333 | Entry $entry, |
| 334 | Container $entryOwner, |
| 335 | Container $requester, |
| 336 | ): array { |
| 337 | return match ($entry->getLifetime()) { |
| 338 | Lifetime::Shared => [$entryOwner, $entryOwner], |
| 339 | Lifetime::Scoped => [$requester, $requester], |
| 340 | Lifetime::Transient => [null, $requester], |
| 341 | }; |
| 342 | } |
| 343 | |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 351 | $constructor = $entry->getConstructor(); |
| 352 | $args = $entry->getArgs(); |
| 353 | |
| 354 | if (isset($args)) { |
| 355 | // Don't autowire if $args are given |
| 356 | if ($args instanceof Closure) { |
| 357 | $args = self::checkedArgs( |
| 358 | $entry, |
| 359 | $args(...new CallableResolver($context->creator)->resolve($args)), |
| 360 | ); |
| 361 | } |
| 362 | |
| 363 | return $this->applyCalls( |
| 364 | $entry, |
| 365 | $context->creator->create( |
| 366 | $value, |
| 367 | predefinedArgs: $args, |
| 368 | constructor: $constructor ?? '', |
| 369 | ), |
| 370 | $context, |
| 371 | ); |
| 372 | } |
| 373 | |
| 374 | return $this->applyCalls( |
| 375 | $entry, |
| 376 | $context->creator->create($value, constructor: $constructor ?? ''), |
| 377 | $context, |
| 378 | ); |
| 379 | } |
| 380 | |
| 381 | if ($context->has($value)) { |
| 382 | return $context->get($value); |
| 383 | } |
| 384 | |
| 385 | throw new NotFoundException('Unresolvable id: ' . $value); |
| 386 | } |
| 387 | |
| 388 | if ($value instanceof Closure) { |
| 389 | $args = $entry->getArgs(); |
| 390 | |
| 391 | if (is_null($args)) { |
| 392 | $args = new CallableResolver($context->creator)->resolve($value); |
| 393 | } elseif ($args instanceof Closure) { |
| 394 | $args = self::checkedArgs($entry, $args()); |
| 395 | } |
| 396 | |
| 397 | return $this->applyCalls($entry, $value(...$args), $context); |
| 398 | } |
| 399 | |
| 400 | if (is_object($value)) { |
| 401 | return $value; |
| 402 | } |
| 403 | |
| 404 | throw new NotFoundException( |
| 405 | "Unresolvable id: {$entry->id} - cannot resolve a definition of type " . get_debug_type($value), |
| 406 | ); |
| 407 | } |
| 408 | |
| 409 | /** @return array<array-key, mixed> */ |
| 410 | private static function checkedArgs(Entry $entry, mixed $args): array |
| 411 | { |
| 412 | if (!is_array($args)) { |
| 413 | throw new ContainerException( |
| 414 | "The args closure of entry '{$entry->id}' must return an array, " . get_debug_type($args) . ' returned', |
| 415 | ); |
| 416 | } |
| 417 | |
| 418 | return $args; |
| 419 | } |
| 420 | |
| 421 | protected function applyCalls(Entry $entry, mixed $value, Container $context): mixed |
| 422 | { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 424 | $callable = [$value, $call->method]; |
| 425 | |
| 426 | if (!is_callable($callable)) { |
| 427 | throw new ContainerException( |
| 428 | "Entry '{$entry->id}' cannot call {$call->method}() on " . get_debug_type($value), |
| 429 | ); |
| 430 | } |
| 431 | |
| 432 | $args = new CallableResolver($context->creator)->resolve($callable, $call->args); |
| 433 | $callable(...$args); |
| 434 | } |
| 435 | |
| 436 | return $value; |
| 437 | } |
| 438 | |
| 439 | /** |
| 440 | * Attempts every reset hook and clears the scope even if hooks fail; the |
| 441 | * failures are collected for the caller. |
| 442 | * |
| 443 | * @param array<int, true> $resetIds |
| 444 | * @param list<Throwable> $failures |
| 445 | */ |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 470 | |
| 471 | /** |
| 472 | * @param array<int, true> $resetIds |
| 473 | * @param list<Throwable> $failures |
| 474 | */ |
| 475 | protected function resetIfNeeded(mixed $value, array &$resetIds, array &$failures): void |
| 476 | { |
| 477 | if (!$value instanceof Resettable) { |
| 478 | return; |
| 479 | } |
| 480 | |
| 481 | $objectId = spl_object_id($value); |
| 482 | |
| 483 | if (isset($resetIds[$objectId])) { |
| 484 | return; |
| 485 | } |
| 486 | |
| 487 | $resetIds[$objectId] = true; |
| 488 | |
| 489 | try { |
| 490 | $value->reset(); |
| 491 | } catch (Throwable $e) { |
| 492 | $failures[] = $e; |
| 493 | } |
| 494 | } |
| 495 | |
| 496 | protected function trackAndReturn(mixed $value): mixed |
| 497 | { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 499 | $this->usedResettables[spl_object_id($value)] = $value; |
| 500 | } |
| 501 | |
| 502 | return $value; |
| 503 | } |
| 504 | |
| 505 | /** @return array{Container, Entry}|null */ |
| 506 | protected function findEntry(string $id): ?array |
| 507 | { |
| 508 | $entry = $this->entries[$id] ?? null; |
| 509 | |
| 510 | if ($entry !== null) { |
| 511 | return [$this, $entry]; |
| 512 | } |
| 513 | |
| 514 | $inherits = $this->inherits; |
| 515 | |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 517 | // Inherited shared entries are cached by the root tag that defines them. |
| 518 | return [$inherits, $inherits->entries[$id]]; |
| 519 | } |
| 520 | |
| 521 | // A tag container only finds tagged entries; get() hands other ids to |
| 522 | // the container owning the tag. |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 524 | } |
| 525 | |
| 526 | protected function root(): Container |
| 527 | { |
| 528 | $container = $this; |
| 529 | |
| 530 | while ($container->parent !== null) { |
| 531 | $container = $container->parent; |
| 532 | } |
| 533 | |
| 534 | return $container; |
| 535 | } |
| 536 | |
| 537 | protected function assertMutable(): void |
| 538 | { |
| 539 | if ($this->sealed) { |
| 540 | throw new ContainerException('The root container is sealed after scope() was called'); |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | protected function seal(): void |
| 545 | { |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 560 | } |
Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not
necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once.
Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 42 | public readonly bool $autowire = true, |
| 43 | ?PsrContainer $container = null, |
| 44 | protected readonly string $tag = '', |
| 45 | protected readonly ?Container $parent = null, |
| 46 | protected readonly bool $isScope = false, |
| 47 | ) { |
| 48 | if ($container) { |
| 48 | if ($container) { |
| 49 | $this->wrappedContainer = $container; |
| 56 | $this->add(Container::class, $this); |
| 57 | $this->creator = new Creator($this); |
| 58 | } |
| 42 | public readonly bool $autowire = true, |
| 43 | ?PsrContainer $container = null, |
| 44 | protected readonly string $tag = '', |
| 45 | protected readonly ?Container $parent = null, |
| 46 | protected readonly bool $isScope = false, |
| 47 | ) { |
| 48 | if ($container) { |
| 53 | $this->wrappedContainer = null; |
| 54 | $this->add(PsrContainer::class, $this); |
| 55 | } |
| 56 | $this->add(Container::class, $this); |
| 56 | $this->add(Container::class, $this); |
| 57 | $this->creator = new Creator($this); |
| 58 | } |
| 207 | string $id, |
| 208 | mixed $value = null, |
| 209 | ): Entry { |
| 210 | $this->assertMutable(); |
| 211 | $entry = new Entry($id, $value ?? $id); |
| 212 | $this->entries[$id] = $entry; |
| 213 | unset($this->instances[$id]); |
| 214 | |
| 215 | return $entry; |
| 216 | } |
| 219 | Entry $entry, |
| 220 | ): Entry { |
| 221 | $this->assertMutable(); |
| 222 | $this->entries[$entry->id] = $entry; |
| 223 | unset($this->instances[$entry->id]); |
| 224 | |
| 225 | return $entry; |
| 226 | } |
| 421 | protected function applyCalls(Entry $entry, mixed $value, Container $context): mixed |
| 422 | { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 424 | $callable = [$value, $call->method]; |
| 425 | |
| 426 | if (!is_callable($callable)) { |
| 427 | throw new ContainerException( |
| 428 | "Entry '{$entry->id}' cannot call {$call->method}() on " . get_debug_type($value), |
| 421 | protected function applyCalls(Entry $entry, mixed $value, Container $context): mixed |
| 422 | { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 424 | $callable = [$value, $call->method]; |
| 425 | |
| 426 | if (!is_callable($callable)) { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 424 | $callable = [$value, $call->method]; |
| 425 | |
| 426 | if (!is_callable($callable)) { |
| 427 | throw new ContainerException( |
| 428 | "Entry '{$entry->id}' cannot call {$call->method}() on " . get_debug_type($value), |
| 429 | ); |
| 430 | } |
| 431 | |
| 432 | $args = new CallableResolver($context->creator)->resolve($callable, $call->args); |
| 423 | foreach ($entry->getCalls() as $call) { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 424 | $callable = [$value, $call->method]; |
| 425 | |
| 426 | if (!is_callable($callable)) { |
| 427 | throw new ContainerException( |
| 428 | "Entry '{$entry->id}' cannot call {$call->method}() on " . get_debug_type($value), |
| 429 | ); |
| 430 | } |
| 431 | |
| 432 | $args = new CallableResolver($context->creator)->resolve($callable, $call->args); |
| 433 | $callable(...$args); |
| 434 | } |
| 435 | |
| 436 | return $value; |
| 437 | } |
| 421 | protected function applyCalls(Entry $entry, mixed $value, Container $context): mixed |
| 422 | { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 424 | $callable = [$value, $call->method]; |
| 425 | |
| 426 | if (!is_callable($callable)) { |
| 427 | throw new ContainerException( |
| 428 | "Entry '{$entry->id}' cannot call {$call->method}() on " . get_debug_type($value), |
| 429 | ); |
| 430 | } |
| 431 | |
| 432 | $args = new CallableResolver($context->creator)->resolve($callable, $call->args); |
| 433 | $callable(...$args); |
| 434 | } |
| 435 | |
| 436 | return $value; |
| 437 | } |
| 421 | protected function applyCalls(Entry $entry, mixed $value, Container $context): mixed |
| 422 | { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 423 | foreach ($entry->getCalls() as $call) { |
| 424 | $callable = [$value, $call->method]; |
| 425 | |
| 426 | if (!is_callable($callable)) { |
| 427 | throw new ContainerException( |
| 428 | "Entry '{$entry->id}' cannot call {$call->method}() on " . get_debug_type($value), |
| 429 | ); |
| 430 | } |
| 431 | |
| 432 | $args = new CallableResolver($context->creator)->resolve($callable, $call->args); |
| 433 | $callable(...$args); |
| 434 | } |
| 435 | |
| 436 | return $value; |
| 437 | } |
| 539 | if ($this->sealed) { |
| 540 | throw new ContainerException('The root container is sealed after scope() was called'); |
| 539 | if ($this->sealed) { |
| 542 | } |
| 410 | private static function checkedArgs(Entry $entry, mixed $args): array |
| 411 | { |
| 412 | if (!is_array($args)) { |
| 413 | throw new ContainerException( |
| 414 | "The args closure of entry '{$entry->id}' must return an array, " . get_debug_type($args) . ' returned', |
| 410 | private static function checkedArgs(Entry $entry, mixed $args): array |
| 411 | { |
| 412 | if (!is_array($args)) { |
| 418 | return $args; |
| 419 | } |
| 102 | public function entries(bool $includeContainer = false): array |
| 103 | { |
| 104 | $inherited = $this->inherits?->entries(true) ?? []; |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 107 | : array_values(array_unique([...array_keys($this->entries), ...$inherited])); |
| 108 | |
| 109 | if ($includeContainer) { |
| 110 | return $keys; |
| 102 | public function entries(bool $includeContainer = false): array |
| 103 | { |
| 104 | $inherited = $this->inherits?->entries(true) ?? []; |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 107 | : array_values(array_unique([...array_keys($this->entries), ...$inherited])); |
| 108 | |
| 109 | if ($includeContainer) { |
| 113 | return array_values(array_filter( |
| 114 | $keys, |
| 115 | static fn(string $item): bool => $item !== PsrContainer::class |
| 116 | && !is_subclass_of($item, PsrContainer::class), |
| 117 | )); |
| 118 | } |
| 102 | public function entries(bool $includeContainer = false): array |
| 103 | { |
| 104 | $inherited = $this->inherits?->entries(true) ?? []; |
| 105 | $keys = $inherited === [] |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 107 | : array_values(array_unique([...array_keys($this->entries), ...$inherited])); |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 107 | : array_values(array_unique([...array_keys($this->entries), ...$inherited])); |
| 108 | |
| 109 | if ($includeContainer) { |
| 110 | return $keys; |
| 102 | public function entries(bool $includeContainer = false): array |
| 103 | { |
| 104 | $inherited = $this->inherits?->entries(true) ?? []; |
| 105 | $keys = $inherited === [] |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 107 | : array_values(array_unique([...array_keys($this->entries), ...$inherited])); |
| 105 | $keys = $inherited === [] |
| 106 | ? array_keys($this->entries) |
| 107 | : array_values(array_unique([...array_keys($this->entries), ...$inherited])); |
| 108 | |
| 109 | if ($includeContainer) { |
| 113 | return array_values(array_filter( |
| 114 | $keys, |
| 115 | static fn(string $item): bool => $item !== PsrContainer::class |
| 116 | && !is_subclass_of($item, PsrContainer::class), |
| 117 | )); |
| 118 | } |
| 120 | public function entry(string $id): Entry |
| 121 | { |
| 122 | return ( |
| 123 | $this->entries[$id] |
| 124 | ?? $this->inherits?->entries[$id] |
| 125 | ?? throw new NotFoundException('Unresolvable entry - id: ' . $id) |
| 126 | ); |
| 127 | } |
| 506 | protected function findEntry(string $id): ?array |
| 507 | { |
| 508 | $entry = $this->entries[$id] ?? null; |
| 509 | |
| 510 | if ($entry !== null) { |
| 511 | return [$this, $entry]; |
| 506 | protected function findEntry(string $id): ?array |
| 507 | { |
| 508 | $entry = $this->entries[$id] ?? null; |
| 509 | |
| 510 | if ($entry !== null) { |
| 514 | $inherits = $this->inherits; |
| 515 | |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 518 | return [$inherits, $inherits->entries[$id]]; |
| 506 | protected function findEntry(string $id): ?array |
| 507 | { |
| 508 | $entry = $this->entries[$id] ?? null; |
| 509 | |
| 510 | if ($entry !== null) { |
| 514 | $inherits = $this->inherits; |
| 515 | |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 524 | } |
| 506 | protected function findEntry(string $id): ?array |
| 507 | { |
| 508 | $entry = $this->entries[$id] ?? null; |
| 509 | |
| 510 | if ($entry !== null) { |
| 514 | $inherits = $this->inherits; |
| 515 | |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 524 | } |
| 506 | protected function findEntry(string $id): ?array |
| 507 | { |
| 508 | $entry = $this->entries[$id] ?? null; |
| 509 | |
| 510 | if ($entry !== null) { |
| 514 | $inherits = $this->inherits; |
| 515 | |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 518 | return [$inherits, $inherits->entries[$id]]; |
| 506 | protected function findEntry(string $id): ?array |
| 507 | { |
| 508 | $entry = $this->entries[$id] ?? null; |
| 509 | |
| 510 | if ($entry !== null) { |
| 514 | $inherits = $this->inherits; |
| 515 | |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 524 | } |
| 506 | protected function findEntry(string $id): ?array |
| 507 | { |
| 508 | $entry = $this->entries[$id] ?? null; |
| 509 | |
| 510 | if ($entry !== null) { |
| 514 | $inherits = $this->inherits; |
| 515 | |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 516 | if ($inherits !== null && isset($inherits->entries[$id])) { |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 523 | return $this->tag === '' ? $this->parent?->findEntry($id) : null; |
| 524 | } |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 134 | return $this->trackAndReturn($this->instances[$id]); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 140 | return $this->trackAndReturn( |
| 141 | $this->resolveEntry( |
| 142 | entryOwner: $resolved[0], |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 154 | return $this->parent->get($id); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 160 | return $this->trackAndReturn($wrappedContainer->get($id)); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 181 | throw new NotFoundException('Unresolvable id: ' . $id); |
| 182 | } |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 181 | throw new NotFoundException('Unresolvable id: ' . $id); |
| 182 | } |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 181 | throw new NotFoundException('Unresolvable id: ' . $id); |
| 182 | } |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 154 | return $this->parent->get($id); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 160 | return $this->trackAndReturn($wrappedContainer->get($id)); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 181 | throw new NotFoundException('Unresolvable id: ' . $id); |
| 182 | } |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 181 | throw new NotFoundException('Unresolvable id: ' . $id); |
| 182 | } |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 130 | public function get(string $id): mixed |
| 131 | { |
| 132 | try { |
| 133 | if (array_key_exists($id, $this->instances)) { |
| 137 | $resolved = $this->findEntry($id); |
| 138 | |
| 139 | if ($resolved !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 150 | if ($this->tag !== '' && $this->parent !== null) { |
| 157 | $wrappedContainer = $this->root()->wrappedContainer; |
| 158 | |
| 159 | if ($wrappedContainer?->has($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 164 | if ($this->autowire && class_exists($id)) { |
| 165 | return $this->trackAndReturn($this->creator->create($id)); |
| 181 | throw new NotFoundException('Unresolvable id: ' . $id); |
| 182 | } |
| 167 | } catch (WireException $e) { |
| 168 | throw new NotFoundException( |
| 169 | 'Unresolvable id: ' . $id . ' - Details: ' . $e->getMessage(), |
| 167 | } catch (WireException $e) { |
| 172 | } catch (ContainerExceptionInterface $e) { |
| 173 | throw $e; |
| 167 | } catch (WireException $e) { |
| 172 | } catch (ContainerExceptionInterface $e) { |
| 174 | } catch (Throwable $e) { |
| 175 | throw new ContainerException( |
| 176 | 'Unresolvable id: ' . $id . ' - ' . $e->getMessage(), |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 91 | public function has(string $id): bool |
| 92 | { |
| 93 | return ( |
| 94 | isset($this->entries[$id]) |
| 95 | || isset($this->inherits?->entries[$id]) |
| 96 | || $this->parent?->has($id) |
| 97 | || $this->wrappedContainer?->has($id) |
| 98 | ); |
| 99 | } |
| 189 | public function instance(string $class): object |
| 190 | { |
| 191 | /** @var mixed $value */ |
| 192 | $value = $this->get($class); |
| 193 | |
| 194 | if (!$value instanceof $class) { |
| 195 | throw new ContainerException( |
| 196 | "Entry '{$class}' resolves to " . get_debug_type($value) . ', not an instance of it', |
| 189 | public function instance(string $class): object |
| 190 | { |
| 191 | /** @var mixed $value */ |
| 192 | $value = $this->get($class); |
| 193 | |
| 194 | if (!$value instanceof $class) { |
| 200 | return $value; |
| 201 | } |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 351 | $constructor = $entry->getConstructor(); |
| 352 | $args = $entry->getArgs(); |
| 353 | |
| 354 | if (isset($args)) { |
| 356 | if ($args instanceof Closure) { |
| 357 | $args = self::checkedArgs( |
| 358 | $entry, |
| 359 | $args(...new CallableResolver($context->creator)->resolve($args)), |
| 360 | ); |
| 361 | } |
| 362 | |
| 363 | return $this->applyCalls( |
| 363 | return $this->applyCalls( |
| 364 | $entry, |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 351 | $constructor = $entry->getConstructor(); |
| 352 | $args = $entry->getArgs(); |
| 353 | |
| 354 | if (isset($args)) { |
| 356 | if ($args instanceof Closure) { |
| 363 | return $this->applyCalls( |
| 364 | $entry, |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 351 | $constructor = $entry->getConstructor(); |
| 352 | $args = $entry->getArgs(); |
| 353 | |
| 354 | if (isset($args)) { |
| 374 | return $this->applyCalls( |
| 375 | $entry, |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 381 | if ($context->has($value)) { |
| 382 | return $context->get($value); |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 381 | if ($context->has($value)) { |
| 385 | throw new NotFoundException('Unresolvable id: ' . $value); |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 351 | $constructor = $entry->getConstructor(); |
| 352 | $args = $entry->getArgs(); |
| 353 | |
| 354 | if (isset($args)) { |
| 356 | if ($args instanceof Closure) { |
| 357 | $args = self::checkedArgs( |
| 358 | $entry, |
| 359 | $args(...new CallableResolver($context->creator)->resolve($args)), |
| 360 | ); |
| 361 | } |
| 362 | |
| 363 | return $this->applyCalls( |
| 363 | return $this->applyCalls( |
| 364 | $entry, |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 351 | $constructor = $entry->getConstructor(); |
| 352 | $args = $entry->getArgs(); |
| 353 | |
| 354 | if (isset($args)) { |
| 356 | if ($args instanceof Closure) { |
| 363 | return $this->applyCalls( |
| 364 | $entry, |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 351 | $constructor = $entry->getConstructor(); |
| 352 | $args = $entry->getArgs(); |
| 353 | |
| 354 | if (isset($args)) { |
| 374 | return $this->applyCalls( |
| 375 | $entry, |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 381 | if ($context->has($value)) { |
| 382 | return $context->get($value); |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 350 | if (class_exists($value)) { |
| 381 | if ($context->has($value)) { |
| 385 | throw new NotFoundException('Unresolvable id: ' . $value); |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 388 | if ($value instanceof Closure) { |
| 389 | $args = $entry->getArgs(); |
| 390 | |
| 391 | if (is_null($args)) { |
| 391 | if (is_null($args)) { |
| 392 | $args = new CallableResolver($context->creator)->resolve($value); |
| 397 | return $this->applyCalls($entry, $value(...$args), $context); |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 388 | if ($value instanceof Closure) { |
| 389 | $args = $entry->getArgs(); |
| 390 | |
| 391 | if (is_null($args)) { |
| 393 | } elseif ($args instanceof Closure) { |
| 394 | $args = self::checkedArgs($entry, $args()); |
| 395 | } |
| 396 | |
| 397 | return $this->applyCalls($entry, $value(...$args), $context); |
| 397 | return $this->applyCalls($entry, $value(...$args), $context); |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 388 | if ($value instanceof Closure) { |
| 389 | $args = $entry->getArgs(); |
| 390 | |
| 391 | if (is_null($args)) { |
| 393 | } elseif ($args instanceof Closure) { |
| 397 | return $this->applyCalls($entry, $value(...$args), $context); |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 388 | if ($value instanceof Closure) { |
| 400 | if (is_object($value)) { |
| 401 | return $value; |
| 344 | protected function materialize(Entry $entry, Container $context): mixed |
| 345 | { |
| 346 | /** @var mixed $value */ |
| 347 | $value = $entry->definition(); |
| 348 | |
| 349 | if (is_string($value)) { |
| 388 | if ($value instanceof Closure) { |
| 400 | if (is_object($value)) { |
| 404 | throw new NotFoundException( |
| 405 | "Unresolvable id: {$entry->id} - cannot resolve a definition of type " . get_debug_type($value), |
| 406 | ); |
| 407 | } |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 270 | return $this->new($value, ...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 276 | return new $value(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 284 | return new $id(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 284 | return new $id(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 276 | return new $value(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 284 | return new $id(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 284 | return new $id(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 269 | if (interface_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 273 | if (class_exists($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 284 | return new $id(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 284 | return new $id(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 266 | $value = $entry->definition(); |
| 267 | |
| 268 | if (is_string($value)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 284 | return new $id(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 284 | return new $id(...$args); |
| 260 | public function new(string $id, mixed ...$args): object |
| 261 | { |
| 262 | $entry = $this->entries[$id] ?? null; |
| 263 | |
| 264 | if ($entry) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 281 | if (class_exists($id)) { |
| 287 | throw new NotFoundException('Cannot instantiate ' . $id); |
| 288 | } |
| 77 | if (!$this->isScope) { |
| 78 | return; |
| 77 | if (!$this->isScope) { |
| 81 | $resetIds = []; |
| 82 | $failures = []; |
| 83 | $this->resetScope($resetIds, $failures); |
| 84 | |
| 85 | if ($failures !== []) { |
| 86 | throw new ResetFailed($failures); |
| 77 | if (!$this->isScope) { |
| 81 | $resetIds = []; |
| 82 | $failures = []; |
| 83 | $this->resetScope($resetIds, $failures); |
| 84 | |
| 85 | if ($failures !== []) { |
| 88 | } |
| 475 | protected function resetIfNeeded(mixed $value, array &$resetIds, array &$failures): void |
| 476 | { |
| 477 | if (!$value instanceof Resettable) { |
| 478 | return; |
| 475 | protected function resetIfNeeded(mixed $value, array &$resetIds, array &$failures): void |
| 476 | { |
| 477 | if (!$value instanceof Resettable) { |
| 481 | $objectId = spl_object_id($value); |
| 482 | |
| 483 | if (isset($resetIds[$objectId])) { |
| 484 | return; |
| 475 | protected function resetIfNeeded(mixed $value, array &$resetIds, array &$failures): void |
| 476 | { |
| 477 | if (!$value instanceof Resettable) { |
| 481 | $objectId = spl_object_id($value); |
| 482 | |
| 483 | if (isset($resetIds[$objectId])) { |
| 487 | $resetIds[$objectId] = true; |
| 488 | |
| 489 | try { |
| 490 | $value->reset(); |
| 494 | } |
| 491 | } catch (Throwable $e) { |
| 492 | $failures[] = $e; |
| 493 | } |
| 494 | } |
| 494 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 446 | protected function resetScope(array &$resetIds, array &$failures): void |
| 447 | { |
| 448 | // $instances stores mixed values by design, so foreach assigns mixed to $instance. |
| 449 | /** @psalm-suppress MixedAssignment */ |
| 450 | foreach ($this->instances as $instance) { |
| 450 | foreach ($this->instances as $instance) { |
| 451 | $this->resetIfNeeded($instance, $resetIds, $failures); |
| 452 | } |
| 453 | |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 454 | foreach ($this->usedResettables as $usedResettable) { |
| 455 | $this->resetIfNeeded($usedResettable, $resetIds, $failures); |
| 456 | } |
| 457 | |
| 458 | // A scope's tags inherit isScope from it, so all of them are scopes. |
| 459 | foreach ($this->tags as $tagContainer) { |
| 459 | foreach ($this->tags as $tagContainer) { |
| 460 | $tagContainer->resetScope($resetIds, $failures); |
| 461 | } |
| 462 | |
| 463 | $this->instances = []; |
| 464 | $this->entries = []; |
| 465 | $this->tags = []; |
| 466 | $this->usedResettables = []; |
| 467 | $this->add(PsrContainer::class, $this); |
| 468 | $this->add(Container::class, $this); |
| 469 | } |
| 333 | Entry $entry, |
| 334 | Container $entryOwner, |
| 335 | Container $requester, |
| 336 | ): array { |
| 337 | return match ($entry->getLifetime()) { |
| 338 | Lifetime::Shared => [$entryOwner, $entryOwner], |
| 339 | Lifetime::Scoped => [$requester, $requester], |
| 340 | Lifetime::Transient => [null, $requester], |
| 340 | Lifetime::Transient => [null, $requester], |
| 340 | Lifetime::Transient => [null, $requester], |
| 333 | Entry $entry, |
| 334 | Container $entryOwner, |
| 335 | Container $requester, |
| 336 | ): array { |
| 337 | return match ($entry->getLifetime()) { |
| 338 | Lifetime::Shared => [$entryOwner, $entryOwner], |
| 339 | Lifetime::Scoped => [$requester, $requester], |
| 340 | Lifetime::Transient => [null, $requester], |
| 340 | Lifetime::Transient => [null, $requester], |
| 340 | Lifetime::Transient => [null, $requester], |
| 341 | }; |
| 342 | } |
| 333 | Entry $entry, |
| 334 | Container $entryOwner, |
| 335 | Container $requester, |
| 336 | ): array { |
| 337 | return match ($entry->getLifetime()) { |
| 338 | Lifetime::Shared => [$entryOwner, $entryOwner], |
| 339 | Lifetime::Scoped => [$requester, $requester], |
| 339 | Lifetime::Scoped => [$requester, $requester], |
| 340 | Lifetime::Transient => [null, $requester], |
| 341 | }; |
| 342 | } |
| 333 | Entry $entry, |
| 334 | Container $entryOwner, |
| 335 | Container $requester, |
| 336 | ): array { |
| 337 | return match ($entry->getLifetime()) { |
| 338 | Lifetime::Shared => [$entryOwner, $entryOwner], |
| 338 | Lifetime::Shared => [$entryOwner, $entryOwner], |
| 340 | Lifetime::Transient => [null, $requester], |
| 341 | }; |
| 342 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 297 | return $entry->definition(); |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 301 | throw new ContainerException( |
| 302 | "Scoped entry '{$id}' cannot be resolved by the root container after scope() was called, " |
| 303 | . 'as every scope would share that instance. It is most likely a dependency of a shared ' |
| 304 | . 'entry: make that entry scoped or transient, or resolve the entry from a scope.', |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 301 | throw new ContainerException( |
| 302 | "Scoped entry '{$id}' cannot be resolved by the root container after scope() was called, " |
| 303 | . 'as every scope would share that instance. It is most likely a dependency of a shared ' |
| 304 | . 'entry: make that entry scoped or transient, or resolve the entry from a scope.', |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 301 | throw new ContainerException( |
| 302 | "Scoped entry '{$id}' cannot be resolved by the root container after scope() was called, " |
| 303 | . 'as every scope would share that instance. It is most likely a dependency of a shared ' |
| 304 | . 'entry: make that entry scoped or transient, or resolve the entry from a scope.', |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 301 | throw new ContainerException( |
| 302 | "Scoped entry '{$id}' cannot be resolved by the root container after scope() was called, " |
| 303 | . 'as every scope would share that instance. It is most likely a dependency of a shared ' |
| 304 | . 'entry: make that entry scoped or transient, or resolve the entry from a scope.', |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 315 | return $cacheContainer->instances[$id]; |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 323 | $cacheContainer->instances[$id] = $result; |
| 324 | } |
| 325 | |
| 326 | return $result; |
| 326 | return $result; |
| 327 | } |
| 291 | Container $entryOwner, |
| 292 | Entry $entry, |
| 293 | string $id, |
| 294 | Container $requester, |
| 295 | ): mixed { |
| 296 | if ($entry->shouldReturnValue()) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 300 | if ($entry->getLifetime() === Lifetime::Scoped && !$requester->isScope && $requester->sealed) { |
| 308 | [$cacheContainer, $resolutionContext] = $this->resolutionContainers( |
| 309 | $entry, |
| 310 | $entryOwner, |
| 311 | $requester, |
| 312 | ); |
| 313 | |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 314 | if ($cacheContainer !== null && array_key_exists($id, $cacheContainer->instances)) { |
| 320 | $result = $this->materialize($entry, $resolutionContext); |
| 321 | |
| 322 | if ($cacheContainer !== null) { |
| 326 | return $result; |
| 327 | } |
| 528 | $container = $this; |
| 529 | |
| 530 | while ($container->parent !== null) { |
| 530 | while ($container->parent !== null) { |
| 534 | return $container; |
| 535 | } |
| 528 | $container = $this; |
| 529 | |
| 530 | while ($container->parent !== null) { |
| 530 | while ($container->parent !== null) { |
| 530 | while ($container->parent !== null) { |
| 531 | $container = $container->parent; |
| 530 | while ($container->parent !== null) { |
| 534 | return $container; |
| 535 | } |
| 62 | $root = $this->root(); |
| 63 | |
| 64 | if (!$root->sealed) { |
| 65 | $root->seal(); |
| 66 | } |
| 67 | |
| 68 | return new self( |
| 68 | return new self( |
| 69 | autowire: $root->autowire, |
| 70 | parent: $root, |
| 71 | isScope: true, |
| 72 | ); |
| 73 | } |
| 62 | $root = $this->root(); |
| 63 | |
| 64 | if (!$root->sealed) { |
| 68 | return new self( |
| 69 | autowire: $root->autowire, |
| 70 | parent: $root, |
| 71 | isScope: true, |
| 72 | ); |
| 73 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 546 | $this->sealed = true; |
| 547 | |
| 548 | // Scoped entries resolved before the first scope must not outlive it: |
| 549 | // the sealed container rejects them from now on. |
| 550 | foreach ($this->entries as $id => $entry) { |
| 550 | foreach ($this->entries as $id => $entry) { |
| 551 | if ($entry->getLifetime() === Lifetime::Scoped) { |
| 552 | unset($this->instances[$id]); |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | foreach ($this->tags as $tagContainer) { |
| 556 | foreach ($this->tags as $tagContainer) { |
| 557 | $tagContainer->seal(); |
| 558 | } |
| 559 | } |
| 229 | public function tag(string $tag): Container |
| 230 | { |
| 231 | if (isset($this->tags[$tag])) { |
| 232 | return $this->tags[$tag]; |
| 229 | public function tag(string $tag): Container |
| 230 | { |
| 231 | if (isset($this->tags[$tag])) { |
| 235 | if ($this->sealed) { |
| 238 | $view = new self(autowire: $this->autowire, tag: $tag, parent: $this); |
| 239 | $view->seal(); |
| 240 | |
| 241 | return $view; |
| 229 | public function tag(string $tag): Container |
| 230 | { |
| 231 | if (isset($this->tags[$tag])) { |
| 235 | if ($this->sealed) { |
| 244 | $tagContainer = new self( |
| 245 | autowire: $this->autowire, |
| 246 | tag: $tag, |
| 247 | parent: $this, |
| 248 | isScope: $this->isScope, |
| 249 | ); |
| 250 | |
| 251 | // A scope's tag lists the root tag's registrations and adds its own, |
| 252 | // while untagged ids resolve through the scope. |
| 253 | if ($this->isScope) { |
| 254 | $tagContainer->inherits = $this->root()->tags[$tag] ?? null; |
| 255 | } |
| 256 | |
| 257 | return $this->tags[$tag] = $tagContainer; |
| 257 | return $this->tags[$tag] = $tagContainer; |
| 258 | } |
| 229 | public function tag(string $tag): Container |
| 230 | { |
| 231 | if (isset($this->tags[$tag])) { |
| 235 | if ($this->sealed) { |
| 244 | $tagContainer = new self( |
| 245 | autowire: $this->autowire, |
| 246 | tag: $tag, |
| 247 | parent: $this, |
| 248 | isScope: $this->isScope, |
| 249 | ); |
| 250 | |
| 251 | // A scope's tag lists the root tag's registrations and adds its own, |
| 252 | // while untagged ids resolve through the scope. |
| 253 | if ($this->isScope) { |
| 257 | return $this->tags[$tag] = $tagContainer; |
| 258 | } |
| 496 | protected function trackAndReturn(mixed $value): mixed |
| 497 | { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 499 | $this->usedResettables[spl_object_id($value)] = $value; |
| 500 | } |
| 501 | |
| 502 | return $value; |
| 502 | return $value; |
| 503 | } |
| 496 | protected function trackAndReturn(mixed $value): mixed |
| 497 | { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 502 | return $value; |
| 503 | } |
| 496 | protected function trackAndReturn(mixed $value): mixed |
| 497 | { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 499 | $this->usedResettables[spl_object_id($value)] = $value; |
| 500 | } |
| 501 | |
| 502 | return $value; |
| 502 | return $value; |
| 503 | } |
| 496 | protected function trackAndReturn(mixed $value): mixed |
| 497 | { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 498 | if ($this->isScope && $value instanceof Resettable) { |
| 502 | return $value; |
| 503 | } |
| 115 | static fn(string $item): bool => $item !== PsrContainer::class |
| 116 | && !is_subclass_of($item, PsrContainer::class), |
| 116 | && !is_subclass_of($item, PsrContainer::class), |
| 115 | static fn(string $item): bool => $item !== PsrContainer::class |
| 116 | && !is_subclass_of($item, PsrContainer::class), |