Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
declare(strict_types=1);
4
 
5
namespace DI;
6
 
7
use DI\Compiler\RequestedEntryHolder;
8
use DI\Definition\Definition;
9
use DI\Definition\Exception\InvalidDefinition;
10
use DI\Invoker\FactoryParameterResolver;
11
use Invoker\Exception\NotCallableException;
12
use Invoker\Exception\NotEnoughParametersException;
13
use Invoker\Invoker;
14
use Invoker\InvokerInterface;
15
use Invoker\ParameterResolver\AssociativeArrayResolver;
16
use Invoker\ParameterResolver\DefaultValueResolver;
17
use Invoker\ParameterResolver\NumericArrayResolver;
18
use Invoker\ParameterResolver\ResolverChain;
19
 
20
/**
21
 * Compiled version of the dependency injection container.
22
 *
23
 * @author Matthieu Napoli <matthieu@mnapoli.fr>
24
 */
25
abstract class CompiledContainer extends Container
26
{
27
    /**
28
     * This const is overridden in child classes (compiled containers).
29
     * @var array
30
     */
31
    protected const METHOD_MAPPING = [];
32
 
33
    private ?InvokerInterface $factoryInvoker = null;
34
 
35
    public function get(string $id) : mixed
36
    {
37
        // Try to find the entry in the singleton map
38
        if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) {
39
            return $this->resolvedEntries[$id];
40
        }
41
 
42
        /** @psalm-suppress UndefinedConstant */
43
        $method = static::METHOD_MAPPING[$id] ?? null;
44
 
45
        // If it's a compiled entry, then there is a method in this class
46
        if ($method !== null) {
47
            // Check if we are already getting this entry -> circular dependency
48
            if (isset($this->entriesBeingResolved[$id])) {
49
                throw new DependencyException("Circular dependency detected while trying to resolve entry '$id'");
50
            }
51
            $this->entriesBeingResolved[$id] = true;
52
 
53
            try {
54
                $value = $this->$method();
55
            } finally {
56
                unset($this->entriesBeingResolved[$id]);
57
            }
58
 
59
            // Store the entry to always return it without recomputing it
60
            $this->resolvedEntries[$id] = $value;
61
 
62
            return $value;
63
        }
64
 
65
        return parent::get($id);
66
    }
67
 
68
    public function has(string $id) : bool
69
    {
70
        // The parent method is overridden to check in our array, it avoids resolving definitions
71
        /** @psalm-suppress UndefinedConstant */
72
        if (isset(static::METHOD_MAPPING[$id])) {
73
            return true;
74
        }
75
 
76
        return parent::has($id);
77
    }
78
 
79
    protected function setDefinition(string $name, Definition $definition) : void
80
    {
81
        // It needs to be forbidden because that would mean get() must go through the definitions
82
        // every time, which kinds of defeats the performance gains of the compiled container
83
        throw new \LogicException('You cannot set a definition at runtime on a compiled container. You can either put your definitions in a file, disable compilation or ->set() a raw value directly (PHP object, string, int, ...) instead of a PHP-DI definition.');
84
    }
85
 
86
    /**
87
     * Invoke the given callable.
88
     */
89
    protected function resolveFactory($callable, $entryName, array $extraParameters = []) : mixed
90
    {
91
        // Initialize the factory resolver
92
        if (! $this->factoryInvoker) {
93
            $parameterResolver = new ResolverChain([
94
                new AssociativeArrayResolver,
95
                new FactoryParameterResolver($this->delegateContainer),
96
                new NumericArrayResolver,
97
                new DefaultValueResolver,
98
            ]);
99
 
100
            $this->factoryInvoker = new Invoker($parameterResolver, $this->delegateContainer);
101
        }
102
 
103
        $parameters = [$this->delegateContainer, new RequestedEntryHolder($entryName)];
104
 
105
        $parameters = array_merge($parameters, $extraParameters);
106
 
107
        try {
108
            return $this->factoryInvoker->call($callable, $parameters);
109
        } catch (NotCallableException $e) {
110
            throw new InvalidDefinition("Entry \"$entryName\" cannot be resolved: factory " . $e->getMessage());
111
        } catch (NotEnoughParametersException $e) {
112
            throw new InvalidDefinition("Entry \"$entryName\" cannot be resolved: " . $e->getMessage());
113
        }
114
    }
115
}