Completed
Push — master ( 947d3c...cb14bc )
by Taosikai
14:43 queued 02:08
created

testInterfaceBindForClassMethodContext()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 10
nc 1
nop 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 16 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
namespace Slince\Di\Tests;
3
4
use Slince\Di\Container;
5
use Slince\Di\Definition;
6
use Slince\Di\Exception\DependencyInjectionException;
7
use Slince\Di\Reference;
8
use Slince\Di\Tests\TestClass\Actor;
9
use Slince\Di\Tests\TestClass\ActorInterface;
10
use Slince\Di\Tests\TestClass\Actress;
11
use Slince\Di\Tests\TestClass\Director;
12
use Slince\Di\Tests\TestClass\Movie;
13
14
error_reporting(E_ALL ^ E_USER_DEPRECATED);
15
16
class ContainerTest extends \PHPUnit_Framework_TestCase
17
{
18
    public function getContainer()
19
    {
20
        return new Container();
21
    }
22
23
    /**
24
     * 自定义闭包或者工厂方法代理
25
     */
26
    public function testDelegate()
27
    {
28
        $container = $this->getContainer();
29
        $container->delegate('director1', function () {
30
            return new Director('James', 26);
31
        });
32
        $this->assertInstanceOf(Director::class, $container->get('director1'));
33
        $container->delegate('director2', [Director::class, 'factory']); //或者 'Slince\Di\Tests\TestClass\Director::factory'
34
        $this->assertInstanceOf(Director::class, $container->get('director2'));
35
    }
36
37
    /**
38
     * 测试对象绑定,对象绑定结果是单例
39
     */
40
    public function testInstance()
41
    {
42
        $container = $this->getContainer();
43
        $director = new Director();
44
        $container->instance('director', $director);
45
        $this->assertInstanceOf(Director::class, $container->get('director'));
46
        $this->assertTrue($container->get('director') === $director);
47
        //instance只能是单例
48
        $this->assertTrue($container->get('director') === $container->get('director'));
49
    }
50
51
    public function testDefine()
52
    {
53
        $container = $this->getContainer();
54
        $container->define('director', Director::class, [0 => 'Bob', 1 => 45]);
55
        $this->assertInstanceOf(Director::class, $director = $container->get('director'));
56
        $this->assertEquals('Bob', $director->getName());
57
        $this->assertEquals(45, $director->getAge());
58
    }
59
60
    /**
61
     * @deprecated
62
     */
63
    public function testSetDefinition()
64
    {
65
        $container = $this->getContainer();
66
        $container->setDefinition('director', new Definition(Director::class, [
0 ignored issues
show
Deprecated Code introduced by
The method Slince\Di\Container::setDefinition() has been deprecated with message: Will be protected, Use define & share or set instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
67
            'name' => 'Bob',
68
            'age' => 45
69
        ]));
70
        $this->assertInstanceOf(Director::class, $director = $container->get('director'));
71
        $this->assertEquals('Bob', $director->getName());
72
        $this->assertEquals(45, $director->getAge());
73
    }
74
75
    /**
76
     * 类名<=>别名,interface <=> implement绑定
77
     */
78
    public function testSimpleBind()
79
    {
80
        $container = $this->getContainer();
81
        //简单的别名绑定
82
        $container->bind('director', Director::class);
83
        $this->assertInstanceOf(Director::class, $container->get('director'));
84
    }
85
86
    /**
87
     * {@deprecated}
88
     */
89
    public function alias()
90
    {
91
        $container = $this->getContainer();
92
        //兼容旧版本别名绑定
93
        $container->alias('director', Director::class);
0 ignored issues
show
Deprecated Code introduced by
The method Slince\Di\Container::alias() has been deprecated with message: duplication,use bind instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
94
        $this->assertInstanceOf(Director::class, $container->get('director'));
95
    }
96
97
    /**
98
     * 绑定接口与实现
99
     */
100
    public function testInterfaceBind()
101
    {
102
        $container = $this->getContainer();
103
        //接口与实现;类绑定
104
        $container->bind(ActorInterface::class, Actor::class);
105
        //直接获取接口实例
106
        $this->assertInstanceOf(ActorInterface::class, $container->get(ActorInterface::class));
107
        $this->assertInstanceOf(Actor::class, $container->get(ActorInterface::class));
108
109
        //获取依赖该接口的类实例
110
        $movie = $container->get(Movie::class);
111
        $this->assertInstanceOf(Movie::class, $movie);
112
        $this->assertInstanceOf(Actor::class, $movie->getActor());
113
    }
114
115
    /**
116
     * 为类设置接口依赖
117
     */
118
    public function testInterfaceBindForClassContext()
119
    {
120
        $container = $this->getContainer();
121
        //为Movie类声明接口实际指向
122
        $container->bind(ActorInterface::class, Actor::class, Movie::class);
123
        //获取依赖该接口的类实例,由于构造方法与setter皆是类依赖故container可以自动解决
124
        $container->define('movie', Movie::class, [], [
125
            'setActress' => []
126
        ]);
127
128
        $movie = $container->get('movie');
129
        $this->assertInstanceOf(Movie::class, $movie);
130
        $this->assertInstanceOf(Actor::class, $movie->getActor());
131
        $this->assertInstanceOf(Actor::class, $movie->getActress());
132
133
        //直接获取接口实例,会报出异常
134
        $this->setExpectedException(DependencyInjectionException::class);
135
        $this->assertInstanceOf(Actor::class, $container->get(ActorInterface::class));
136
    }
137
138
    /**
139
     * 为类方法设置接口依赖
140
     */
141
    public function testInterfaceBindForClassMethodContext()
142
    {
143
        $container = $this->getContainer();
144
        //为Movie类声明接口依赖
145
        $container->bind(ActorInterface::class, Actor::class, [Movie::class, '__construct']); //构造函数
146
        $container->bind(ActorInterface::class, Actress::class, [Movie::class, 'setActress']); //setter方法
147
148
        //获取依赖该接口的类实例,由于构造方法与setter皆是类依赖故container可以自动解决
149
        $container->define('movie', Movie::class, [], [
150
            'setActress' => []
151
        ]);
152
        $movie = $container->get('movie');
153
        $this->assertInstanceOf(Movie::class, $movie);
154
        $this->assertInstanceOf(Actor::class, $movie->getActor());
155
        $this->assertInstanceOf(Actress::class, $movie->getActress());
156
    }
157
158
    public function testShare()
159
    {
160
        $container = $this->getContainer();
161
        $container->delegate('director', function () {
162
            return new Director('James', 26);
163
        });
164
        $container->share('director');
165
        $this->assertInstanceOf(Director::class, $container->get('director'));
166
        $this->assertTrue($container->get('director') === $container->get('director'));
167
168
        //兼容旧的api,已提示废除
169
        $container->share('director2', function () {
170
            return new Director('James', 26);
171
        });
172
        $this->assertTrue($container->get('director2') === $container->get('director2'));
173
    }
174
175
    public function testSet()
176
    {
177
        $container = $this->getContainer();
178
        //Similar to delegate
179
        $container->set('director', function () {
180
            return new Director('James', 26);
181
        });
182
        $this->assertInstanceOf(Director::class, $container->get('director'));
183
        $this->assertFalse($container->get('director') === $container->get('director'));
184
185
        //Similar to bind
186
        $container->set('director2', Director::class);
187
        $this->assertInstanceOf(Director::class, $container->get('director2'));
188
        $this->assertFalse($container->get('director2') === $container->get('director2'));
189
190
        //Similar to instance
191
        $container->set('director3', new Director());
192
        $this->assertInstanceOf(Director::class, $container->get('director3'));
193
        $this->assertTrue($container->get('director3') === $container->get('director3'));
194
195
        //Similar to define
196
        $container->set('director4', new Definition(Director::class, [
197
            'name' => 'Bob',
198
            'age' => 45
199
        ]));
200
        $this->assertInstanceOf(Director::class, $container->get('director4'));
201
        $this->assertFalse($container->get('director4') === $container->get('director4'));
202
    }
203
204
    public function testSetWithShare()
205
    {
206
        $container = $this->getContainer();
207
        //Similar to delegate
208
        $container->set('director', function () {
209
            return new Director('James', 26);
210
        }, true);
211
        $this->assertInstanceOf(Director::class, $container->get('director'));
212
        $this->assertTrue($container->get('director') === $container->get('director'));
213
214
        //Similar to bind
215
        $container->set('director2', Director::class, true);
216
        $this->assertInstanceOf(Director::class, $container->get('director2'));
217
        $this->assertTrue($container->get('director2') === $container->get('director2'));
218
219
        //Similar to instance
220
        $container->set('director3', new Director(), true);
221
        $this->assertInstanceOf(Director::class, $container->get('director3'));
222
        $this->assertTrue($container->get('director3') === $container->get('director3'));
223
224
        //Similar to define
225
        $container->set('director4', new Definition(Director::class, [
226
            'name' => 'Bob',
227
            'age' => 45
228
        ]), true);
229
        $this->assertInstanceOf(Director::class, $container->get('director4'));
230
        $this->assertTrue($container->get('director4') === $container->get('director4'));
231
    }
232
233
    public function testGetWithArguments()
234
    {
235
        $container = $this->getContainer();
236
        $director = $container->get(Director::class, [
237
            'age' => 26
238
        ]);
239
        //变量名索引
240
        $this->assertEquals(26, $director->getAge());
241
        //数字索引
242
        $director = $container->get(Director::class, [
243
            1 => 18
244
        ]);
245
        $this->assertEquals(18, $director->getAge());
246
    }
247
248
    public function testGetWithReference()
249
    {
250
        $container = $this->getContainer();
251
        $container->set('director', new Director('Bob', 45));
252
        $container->bind(ActorInterface::class, Actor::class);
253
254
        $movie = $container->get(Movie::class);
255
        $this->assertEquals(18, $movie->getDirector()->getAge()); //Defaults age
256
257
        $movie = $container->get(Movie::class, [
258
            new Reference('director')
259
        ]);
260
        $this->assertEquals('Bob', $movie->getDirector()->getName());
261
        $this->assertEquals(45, $movie->getDirector()->getAge());
262
    }
263
264
    public function testSimpleGlobalParameter()
265
    {
266
        $container = $this->getContainer();
267
        $container->setParameters([
268
            'directorName' => 'James'
269
        ]);
270
        $container->delegate('director', function (Container $container) {
271
            return new Director($container->getParameter('directorName'), 26);
272
        });
273
        $this->assertEquals('James', $container->get('director')->getName());
274
    }
275
276
    public function testGlobalParameter()
277
    {
278
        $container = $this->getContainer();
279
        $container->setParameters([
280
            'directorName' => 'James',
281
            'director' => [ //支持点号获取深度数据结构
282
                'age' => 26
283
            ]
284
        ]);
285
        //支持点号访问
286
        $container->define('director', Director::class, [
287
            '%directorName%',
288
            '%director.age%'
289
        ]);
290
        $this->assertEquals('James', $container->get('director')->getName());
291
        $this->assertEquals(26, $container->get('director')->getAge());
292
293
        //在get操作时传入参数
294
        $this->assertEquals(26, $container->get(Director::class, [
295
            'age' => '%director.age%'
296
        ])->getAge());
297
    }
298
}
299