Test Failed
Pull Request — master (#37)
by Divine Niiquaye
15:08
created

SealedContainer::tagged()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 2
b 0
f 0
nc 2
nop 2
dl 0
loc 5
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of DivineNii opensource projects.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2021 DivineNii (https://divinenii.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Rade\DI;
19
20
use Psr\Container\ContainerInterface;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Rade\DI\ContainerInterface. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
21
use Rade\DI\Exceptions\{ContainerResolutionException, NotFoundServiceException};
22
23
/**
24
 * A fully strict PSR-11 Container Implementation.
25
 *
26
 * This class is meant to be used as parent class for container's builder
27
 * compiled container class.
28
 *
29
 * Again, all services declared, should be autowired. Lazy services are not supported.
30
 *
31
 * @deprecated Performance gain over main container's class is soo little and will be removed before v1
32
 * @author Divine Niiquaye Ibok <[email protected]>
33
 */
34
class SealedContainer implements ContainerInterface
35
{
36
    protected array $loading = [], $services = [], $privates = [], $aliases = [], $types = [], $tags = [];
37
38
    public function __construct()
39
    {
40
        $this->services[AbstractContainer::SERVICE_CONTAINER] = $this;
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function has(string $id): bool
47
    {
48
        return isset($this->types[$this->aliases[$id] ?? $id]);
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function get(string $id, int $invalidBehavior = /* self::EXCEPTION_ON_MULTIPLE_SERVICE */ 1)
55
    {
56
        return $this->services[$id = $this->aliases[$id] ?? $id] ?? $this->doLoad($id, $invalidBehavior);
57
    }
58
59
    /**
60
     * Returns a set of service definition's belonging to a tag.
61
     *
62
     * @param string $tagName
63
     * @param string|null $serviceId If provided, tag value will return instead
64
     *
65
     * @return mixed
66
     */
67
    public function tagged(string $tagName, ?string $serviceId = null)
68
    {
69
        $tags = $this->tags[$tagName] ?? [];
70
71
        return null !== $serviceId ? $tags[$serviceId] ?? [] : $tags;
72
    }
73
74
    /**
75
     * Return the resolved service of an entry.
76
     *
77
     * @return mixed
78
     */
79
    protected function doLoad(string $id, int $invalidBehavior)
80
    {
81
        if (\array_key_exists($id, $this->types)) {
82
            if (1 === \count($autowired = $this->types[$id])) {
83
                return $this->get($autowired[1]);
84
            }
85
86
            if (AbstractContainer::IGNORE_MULTIPLE_SERVICE !== $invalidBehavior && AbstractContainer::EXCEPTION_ON_MULTIPLE_SERVICE === $invalidBehavior) {
87
                \natsort($autowired);
88
                $autowired = \count($autowired) <= 3 ? \implode(', ', $autowired) : $autowired[0] . ', ...' . \end($autowired);
89
90
                throw new ContainerResolutionException(\sprintf('Multiple services of type %s found: %s.', $id, $autowired));
91
            }
92
93
            return \array_map([$this, 'get'], $autowired);
94
        }
95
96
        if (\preg_match('/\[(.*?)?\]$/', $id, $matches, \PREG_UNMATCHED_AS_NULL)) {
97
            $autowired = $this->types[\str_replace($matches[0], '', $id)] ?? [];
98
99
            if (!empty($autowired)) {
100
                if (\is_numeric($k = $matches[1])) {
101
                    $k = $autowired[$k] ?? null;
102
                }
103
104
                return $k ? $this->get($k) : \array_map([$this, 'get'], $autowired);
105
            }
106
        }
107
108
        if (AbstractContainer::NULL_ON_INVALID_SERVICE === $invalidBehavior) {
109
            return null;
110
        }
111
112
        throw new NotFoundServiceException(\sprintf('The "%s" requested service is not defined in container.', $id));
113
    }
114
115
    private function __clone()
116
    {
117
    }
118
}
119