InstanceFactoryTrait   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 5
dl 0
loc 124
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 20 4
A realScopeInfo() 0 11 2
A createInstance() 0 17 2
A initContainer() 0 11 2
1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Di
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Di\Traits;
16
17
use Phossa2\Di\Message\Message;
18
use Phossa2\Di\Resolver\ObjectResolver;
19
use Phossa2\Di\Exception\LogicException;
20
use Phossa2\Di\Interfaces\ScopeInterface;
21
22
/**
23
 * InstanceFactoryTrait
24
 *
25
 * Manufacturing instances for container
26
 *
27
 * @package Phossa2\Di
28
 * @author  Hong Zhang <[email protected]>
29
 * @version 2.0.0
30
 * @since   2.0.0 added
31
 */
32
trait InstanceFactoryTrait
33
{
34
    use ScopeTrait;
35
36
    /**
37
     * instances pool
38
     *
39
     * @var    object[]
40
     * @access protected
41
     */
42
    protected $pool = [];
43
44
    /**
45
     * for loop detection
46
     *
47
     * @var    array
48
     * @access protected
49
     */
50
    protected $loop = [];
51
52
    /**
53
     * @var    int
54
     * @access protected
55
     */
56
    protected $counter = 0;
57
58
    /**
59
     * Get the instance either from the pool or create it
60
     *
61
     * @param  string $id service id with or without the scope
62
     * @param  array $args arguments for the constructor
63
     * @return object
64
     * @throws LogicException if instantiation goes wrong
65
     * @throws RuntimeException if method execution goes wrong
66
     * @access protected
67
     */
68
    protected function getInstance(/*# string */ $id, array $args)
69
    {
70
        // get id & scope info
71
        list($rawId, $scopedId, $scope) = $this->realScopeInfo($id);
72
73
        // get from the pool
74
        if (isset($this->pool[$scopedId])) {
75
            return $this->pool[$scopedId];
76
        }
77
78
        // create instance
79
        $instance = $this->createInstance($rawId, $args);
80
81
        // save in the pool
82
        if (empty($args) && ScopeInterface::SCOPE_SINGLE !== $scope) {
83
            $this->pool[$scopedId] = $instance;
84
        }
85
86
        return $instance;
87
    }
88
89
    /**
90
     * Full scope info with consideration of ancestor instances
91
     *
92
     * @param  string $id
93
     * @return array
94
     * @access protected
95
     */
96
    protected function realScopeInfo(/*# string */ $id)/*# : array */
97
    {
98
        list($rawId, $scope) = $this->scopedInfo($id);
99
100
        // special treatment if $scope is a '#service_id'
101
        if (isset($this->loop[$scope])) {
102
            $scope .= '_' . $this->loop[$scope];
103
        }
104
105
        return [$rawId, $this->scopedId($rawId, $scope), $scope];
106
    }
107
108
    /**
109
     * Create the instance with loop detection
110
     *
111
     * Loop: an instance depends on itself in the creation chain.
112
     *
113
     * @param  string $rawId
114
     * @param  array $args arguments for the constructor if any
115
     * @return object
116
     * @throws LogicException if instantiation goes wrong or loop detected
117
     * @access protected
118
     */
119
    protected function createInstance(/*# string */ $rawId, array $args)
120
    {
121
        // conver 'service_id' to '#service_id'
122
        $serviceId = ObjectResolver::getServiceId($rawId);
123
124
        if (isset($this->loop[$serviceId])) {
125
            throw new LogicException(
126
                Message::get(Message::DI_LOOP_DETECTED, $rawId),
127
                Message::DI_LOOP_DETECTED
128
            );
129
        } else {
130
            $this->loop[$serviceId] = ++$this->counter;
131
            $obj = $this->getFactory()->createInstance($rawId, $args);
132
            unset($this->loop[$serviceId]);
133
            return $obj;
134
        }
135
    }
136
137
    /**
138
     * execute init methods defined in 'di.init' node
139
     *
140
     * @return $this
141
     * @throws RuntimeException if anything goes wrong
142
     * @access protected
143
     */
144
    protected function initContainer()
145
    {
146
        $initNode = $this->getResolver()->getSectionId('', 'init');
147
148
        if ($this->getResolver()->has($initNode)) {
149
            $this->getFactory()->executeMethodBatch(
150
                $this->getResolver()->get($initNode)
151
            );
152
        }
153
        return $this;
154
    }
155
}
156