1 <?php
2
3 //容器类装实例或提供实例的回调函数
4 class Container {
5
6 protected $bindings = [];
7
8 //绑定接口和生成相应实例的回调函数
9 public function bind($abstract, $concrete=null, $shared=false) {
10
11 //如果提供的参数不是回调函数,则产生默认的回调函数
12 if(!$concrete instanceof Closure) {
13 $concrete = $this->getClosure($abstract, $concrete);
14 }
15
16 $this->bindings[$abstract] = compact('concrete', 'shared');
17 }
18
19 //默认生成实例的回调函数
20 protected function getClosure($abstract, $concrete) {
21
22 return function($c) use ($abstract, $concrete) {
23 $method = ($abstract == $concrete) ? 'build' : 'make';
24 return $c->$method($concrete);
25 };
26
27 }
28
29 public function make($abstract) {
30 $concrete = $this->getConcrete($abstract);
31
32 if($this->isBuildable($concrete, $abstract)) {
33 $object = $this->build($concrete);
34 } else {
35 $object = $this->make($concrete);
36 }
37
38 return $object;
39 }
40
41 protected function isBuildable($concrete, $abstract) {
42 return $concrete === $abstract || $concrete instanceof Closure;
43 }
44
45 //获取绑定的回调函数
46 protected function getConcrete($abstract) {
47 if(!isset($this->bindings[$abstract])) {
48 return $abstract;
49 }
50
51 return $this->bindings[$abstract]['concrete'];
52 }
53
54 //实例化对象
55 public function build($concrete) {
56
57 if($concrete instanceof Closure) {
58 return $concrete($this);
59 }
60
61 $reflector = new ReflectionClass($concrete);
62 if(!$reflector->isInstantiable()) {
63 echo $message = "Target [$concrete] is not instantiable";
64 }
65
66 $constructor = $reflector->getConstructor();
67 if(is_null($constructor)) {
68 return new $concrete;
69 }
70
71 $dependencies = $constructor->getParameters();
72 $instances = $this->getDependencies($dependencies);
73
74 return $reflector->newInstanceArgs($instances);
75 }
76
77 //解决通过反射机制实例化对象时的依赖
78 protected function getDependencies($parameters) {
79 $dependencies = [];
80 foreach($parameters as $parameter) {
81 $dependency = $parameter->getClass();
82 if(is_null($dependency)) {
83 $dependencies[] = NULL;
84 } else {
85 $dependencies[] = $this->resolveClass($parameter);
86 }
87 }
88
89 return (array)$dependencies;
90 }
91
92 protected function resolveClass(ReflectionParameter $parameter) {
93 return $this->make($parameter->getClass()->name);
94 }
95
96 }
97
98
99 class Traveller {
100
101 protected $trafficTool;
102
103 public function __construct(Visit $trafficTool) {
104 $this->trafficTool = $trafficTool;
105 }
106
107 public function visitTibet() {
108 $this->trafficTool->go();
109 }
110
111 }
112
113 interface Visit {
114 public function go();
115 }
116
117 class Train implements Visit {
118
119 public function go() {
120 echo "go to Tibet by train !!!";
121 }
122
123 }
124
125 $app = new Container();
126 $app->bind("Visit", "Train");
127 $app->bind("traveller", "Traveller");
128
129
130 $tra = $app->make("traveller");
131 $tra->visitTibet();