Completed
Push — master ( 1e2100...b879f8 )
by Taosikai
14:23
created

ClassDefinitionResolver::invokeMethods()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 18
rs 9.4285
c 1
b 0
f 0
cc 3
eloc 12
nc 3
nop 3
1
<?php
2
/**
3
 * slince dependency injection component
4
 * @author Tao <[email protected]>
5
 */
6
namespace Slince\Di;
7
8
use Slince\Di\Exception\DependencyInjectionException;
9
10
class ClassDefinitionResolver
11
{
12
    /**
13
     * @var Container
14
     */
15
    protected $container;
16
17
    /**
18
     * @param Container $container
19
     */
20
    public function __construct($container)
21
    {
22
        $this->container = $container;
23
    }
24
25
    /**
26
     * @param ClassDefinition $definition
27
     * @param array $arguments
28
     * @return mixed
29
     */
30
    public function resolve(ClassDefinition $definition, $arguments = [])
31
    {
32
        $arguments = array_replace($definition->getArguments(), $arguments);
33
        try {
34
            $reflection = new \ReflectionClass($definition->getClass());
35
        } catch (\ReflectionException $e) {
36
            throw new DependencyInjectionException(sprintf('Class "%s" is invalid', $definition->getClass()));
37
        }
38
        if (!$reflection->isInstantiable()) {
39
            throw new DependencyInjectionException(sprintf("Can not instantiate [%s]", $definition->getClass()));
40
        }
41
        $constructor = $reflection->getConstructor();
42
        if (is_null($constructor)) {
43
            $instance = $reflection->newInstanceWithoutConstructor();
44
        } else {
45
            $constructorArguments = $this->container->resolveFunctionArguments($constructor, $arguments,
46
                $this->container->getContextBindings($definition->getClass(), $constructor->getName())
47
            );
48
            $instance = $reflection->newInstanceArgs($constructorArguments);
49
        }
50
        $this->invokeMethods($definition, $instance, $reflection);
51
        $this->invokeProperties($definition, $instance);
52
        return $instance;
53
    }
54
55
    protected function invokeMethods(ClassDefinition $definition, $instance, \ReflectionClass $reflection)
56
    {
57
        foreach ($definition->getMethodCalls() as $method => $methodArguments) {
58
            try {
59
                $reflectionMethod = $reflection->getMethod($method);
60
            } catch (\ReflectionException $e) {
61
                throw new DependencyInjectionException(sprintf(
62
                    "Class '%s' has no method '%s'",
63
                    $definition->getClass(),
64
                    $method
65
                ));
66
            }
67
            $contextBindings = $this->container->getContextBindings($reflection->name, $method);
68
            $reflectionMethod->invokeArgs($instance, $this->container->resolveFunctionArguments($reflectionMethod,
69
                $methodArguments, $contextBindings
70
            ));
71
        }
72
    }
73
74
    protected function invokeProperties(ClassDefinition $definition, $instance)
75
    {
76
        foreach ($definition->getProperties() as $propertyName => $propertyValue) {
77
            if (property_exists($instance, $propertyName)) {
78
                $instance->$propertyName = $propertyValue;
79
            } else {
80
                throw new DependencyInjectionException(sprintf(
81
                    "Class '%s' has no property '%s'",
82
                    $definition->getClass(),
83
                    $propertyName
84
                ));
85
            }
86
        }
87
    }
88
}