Issues (2)

src/Factory.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace HexMakina\LeMarchand;
4
5
use Psr\Container\ContainerInterface;
6
7
class Factory 
8
{
9
    // store cached instances
10
    private static $instance_cache = [];
11
12
    // Private container used for dependency injection
13
    private $container = null;
14
15
    // Constructor accepting Container Interface
16
    public function __construct(ContainerInterface $container)
17
    {
18
        // Assign given container instance to member variable
19
        $this->container = $container;
20
    }
21
22
    // Function accepting class name and contruction args for builder methods
23
    public function serve($class, $construction_args = null)
24
    {
25
        // Look for cached instance, otherwise try to build new instance
26
        return $this->stock($class)
27
            ?? $this->build($class, $construction_args)
28
            ?? null;
29
    }
30
31
    // Function to store cache instances. Also accepts single instance
32
    public function stock($class, $instance = null)
33
    {
34
        // If an instance was passed in, store it
35
        if (!is_null($instance)) {
36
            self::$instance_cache[$class] = $instance;
37
        }
38
39
        // Return  the instance found in the cache or null if not found
40
        return self::$instance_cache[$class] ?? null;
41
    }
42
43
    // Function to build new Instances from classes 
44
    public function build($class, $construction_args = null)
45
    {
46
        try {
47
            // Create ReflectionClass based on given class
48
            $reflection = new \ReflectionClass($class);
49
            
50
            // Get constructor from ReflectionClass
51
            $constructor = $reflection->getConstructor();
52
            $instance = null;
53
54
            // Create instance depending on existence of constructor
55
            if (is_null($constructor)) {
56
                $instance = $reflection->newInstanceArgs();
57
            } else {
58
                // Check if construction args are empty, 
59
                // if so get them from constructor
60
                if (empty($construction_args)) {
61
                    $construction_args = $this->getConstructorParameters($constructor);
62
                }
63
64
                // Determine how to build instance based on visibility of constructor
65
                $instance = $constructor->isPrivate()
66
                    ? $this->buildSingleton($reflection, $construction_args)
67
                    : $reflection->newInstanceArgs($construction_args);
68
            }
69
70
            // Cache instance for later use
71
            $this->stock($class, $instance);
72
73
            // Return Created Instance
74
            return $instance;
75
        } catch (\ReflectionException $e) {
76
            // Throw an exception based on the ReflectionException message
77
            throw new ContainerException($e->getMessage());
78
        }
79
    }
80
81
    // Function to get Constructor Parameters from given constructor 
82
    private function getConstructorParameters(\ReflectionMethod $constructor)
83
    {
84
        // Init return array
85
        $ret = [];
86
        
87
        foreach ($constructor->getParameters() as $param) {
88
            // Get parameter type, if exists
89
            $id = $param->getType()
90
                ? $param->getType()->getName()
0 ignored issues
show
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

90
                ? $param->getType()->/** @scrutinizer ignore-call */ getName()
Loading history...
91
                : 'settings.Constructor.' . $constructor->class . '.' . $param->getName();
92
            
93
            // Get resource with Id and append to return array
94
            $ret [] = $this->container->get($id);
95
        }
96
97
        // Return array with constructed objects
98
        return $ret;
99
    }
100
101
    // Function to build singletons
102
    private function buildSingleton(\ReflectionClass $rc, $construction_args)
103
    {
104
        // Get first argument as instantiation method 
105
        $singleton_method = $rc->getMethod(array_shift($construction_args));
106
107
        // Get second argument as invocation args
108
        $construction_args = array_shift($construction_args);
109
110
        // Invoke method with arguments
111
        $singleton = $singleton_method->invoke(null, $construction_args);
112
113
        // Return singletion
114
        return $singleton;
115
    }
116
}
117