Phalcon 的 ioc 实现

2016-08-16 16:05:44 +08:00
 lml12377

看 phalcon 的源码,关于 Di :

假设:

$di = new Di();

// set
$di->set('request', function(){
	return new Request();
});

// get
$request = $di->get('request');

看了下大概流程:

1 、 set() 创建 Service 对象

2 、 get() 拿到之前创建的 Service 对象,调用 resolve(),里面 call_user_func() 执行匿名函数

3 、 get() 里给组件 setDI($this) 并返回这个组件对象

里面有个很奇怪的地方:

resolve() 里面会用 \Closure::bind() 把 $di 对象交给匿名函数,接着才 call_user_func ,但是 $di->get() 里面却通过 setDI() 来注入 $di 对象,这是何必呢、、、

既然把 $di 对象 bind() 回去了,我就可以在匿名函数里直接 return new Request($this); 啊,这样每个组件继承一个基类,基类的构造函数负责给自己的 protected $_di; 赋值啊、、、

求解!

di: https://github.com/phalcon/cphalcon/blob/master/phalcon/di.zep

service: https://github.com/phalcon/cphalcon/blob/master/phalcon/di/service.zep

2153 次点击
所在节点    程序员
3 条回复
jerray
2016-08-16 20:22:52 +08:00
1. 只有当 instance 实现了 InjectionAwareInterface 接口的时候才会执行 setDI 。通过 set 方法创建的 Service 对象并没有实现这个接口
2. setShared 只是包装了一下 set : setShared(name, definition) -> set(name, definition, true)
3. 这里的 Service 是具体实现的包装器,根据 definition resolve 出来的对象才是真正运行时用到的 Service
4. shared 组件是单例的, Service 包装器在 resolve 的时候判断当前组件是否是单例,如果是并且已经实例化了,直接返回实例。如果未实例化,会根据 definition 进行实例化
5. 看上去同一个名字的组件只能注册一个
6. 我不会 Zephir

好像并没有哪里奇怪
bombless
2016-08-16 21:25:07 +08:00
它在全局有个默认的 di ,估计最开始设计的时候是所有组件都用这个 di ,后面才改成这样的。

我感觉 phalcon 很多地方都不符合直觉的
lml12377
2016-08-17 09:15:36 +08:00
@jerray 还有个问题,这个 Di 只能算个容器吧,只不过装的 Service 对象(事实上 sharedInstances 装的是具体的组件对象),这也只能算是依赖倒置,并没有实现注入吧?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/299671

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX