container实现

纸上得来终觉浅,得知此事需躬行。

之前看phalcon框架DI的实现方式,觉得很好用,但是由于是c扩展,看不了源码,并不知道是如何实现的,后来看laravel的服务容器,发现是实现了php的SPL接口,然后用这些接口实现的。

一个典型的「container」便是实现了arrayaccess,Demo如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

<?php
namespace skylee;

class A
{

public function say()
{

return __METHOD__;
}

}

class B
{


public function say()
{

return __METHOD__;
}
}

// 容器
class Container implements \arrayaccess
{


private $container = array();

public function __construct(array $array = [])
{

$this->container = $array;
}

public function __get($id)
{

return $this->offsetGet($id);
}

public function offsetSet($offset, $value)
{

if (is_null($offset))
{
$this->container[] = $value;
}
else
{
$this->container[$offset] = $value;
}
}

public function offsetExists($offset)
{

return isset($this->container[$offset]);
}

public function offsetUnset($offset)
{

unset($this->container[$offset]);
}

public function offsetGet($offset)
{

$raw = $this->container[$offset];

return $this->container[$offset] = $raw();
}

public function register($Manage)
{

$Manage->register($this);
}
}

// provide
interface ServiceProvide
{

public function register(Container $container);
}

class ProvideA implements ServiceProvide
{

public function register(Container $container)
{

$container['A'] = function ()
{

return new skylee\A;
};
}
}

class ProvideB implements ServiceProvide
{

public function register(Container $container)
{

$container['B'] = function ()
{

return new skylee\B;
};
}
}

class App extends Container
{

public $service = [
skylee\ProvideA::class,
skylee\ProvideB::class
];

public function __construct()
{

parent::__construct();

$this->registerProvide();
}

public function registerProvide()
{

foreach ($this->service as $v)
{
$this->register(new $v());
}
}
}

$obj = new App();

$a = $obj["A"]->say();

$b = $obj["B"]->say();

var_dump($a);

var_dump($b);