Yii 2.0 框架学习笔记 - 基础抽象

Yii 2.0 base 包里部分类的类图

Yii 框架从 2.0 开始,底层抽象上面发生了一些变化。比如,多了 DI 和 Service Locator 等设计模式相关的抽象。这两天,专门看了下代码,写下一点我的想法。

上面的图是,是我用 Visual Paradigm 画的类图。从图里我们看到,2.0 版本以来,最根部的抽象是一个叫 Configurable 的接口,其主要作用就是说明所有的类都可以用类似 Key-Value 结构来进行配置。除了一些 Helper 的类,绝大部分对象都是 Configurable 的实现。

打开 Configurable 的代码,发现是一个空的接口,所以,我认为作者这是要表达一种抽象层面的概念,并没有实际的用途。查了 Stack-Overflow ,据说这是原自 Java 里的一种惯用做法,不过说实在的,我还是没有太理解,全空用来表达概念,可能是出于某种性能层面的考虑。但是,读起来确实有点故弄玄虚的错觉。看来关于这些概念的说明,也是框架作者的技术债了,现在文档上已经写了,Configurable 接口,真正约定的是构造函数的实现,其要求所有实现此接口的对象,构造函数的最后一个参数,都需要接受一个 $config 配置数组,所以,这个接口才是空的。实现这个接口,等于就是满足这个约定。

顶层的实体抽象其实是 Object,顾名思义,就是对象的基本抽象,对象的本质,应该有属性。于是 Object 主要提供了属性的抽象。这样,Object 就变成了一种非常纯粹的抽象。下面一层是 Component,名义上,这是组件,组件除了是一个对象以外,还有组件应有的核心抽象,是事件和行为。从 Component 的代码里,我们可以看到,它完全重新实现了关于属性的抽象。我想,这么做的原因大概是,Object 在实现属性的时候,只考虑了通用情况的做法,就是属性有对应的 getter 和 setter 进行包装,但是没有考虑到属性可以从 Behaviour 注入的情况,所以,组件完全重新实现了属性的抽象。显然另一种选择是单独实现 Behaviour 注入属性的情况,然后调用父类的普通属性的情况,但是为什么没这么做呢?这个我暂时也没有太多想法,估计也还是出于某种执行效率的考虑吧。

下面一层的抽象是 Service Locator,这是一个单独的对象,主要是 IoC 设计模式的一种实现,其本质是一种全局的注册表,里面记录了所有的 Service 的创建方法和位置。主要是用于在应用执行的过程中动态的引入 Service 的一种方式,使用这种方式,可以解开对特定 Service 的实现的依赖。另外,从 ServiceLocator 的代码里,我们也可以看到,这里还增加了 Lazy Loading 的策略在里面。某个具体的 Service 可以以配置数组的形态存在,直到真的需要的时候才实例化出来。实例化后,会被统一管理。

Module 是业务逻辑的基本组织单位,Module 自己就是一个 ServiceLocator。因为它是一个组织者,也是一个容器,这么抽象也是说得过去的。Module 控制着 Controller 和 View 的生命周期,此外 Module 还可以跟自己嵌套。所以,Module 就是 Yii 框架里,最核心的容器抽象了。帮助更有效的组织代码。

Application 是一种特殊的 Module,它是一个应用,整个系统启动的第一个容器。所以它是 Module 的子类。

另一边,Container 是 DI 设计模式的核心实现,主要就是容器。BaseYii 和 Yii 是全局的 Helper,这里也没看懂的,为啥 BaseYii 是个空类。Yii 这个 Helper 里面包含了 Container 的全局唯一实例,所以,所有的对象实例化的工作是由 Yii 完成的。BaseYii 里实现了很多整个框架通用的功能逻辑,而 Yii 则继承了 BaseYii,Yii 的实现是空的,这个文件会被入口文件引用,Yii 留空的原因,注释里也写了,就是允许程序员实现一些自己的方法来覆盖父类的方法。

看完了 Yii 2.0 的抽象,我们再来回忆一下 1.0 的情况。第一,所有的对象也是可以配置的。但是没有用 Configurable 给把概念显性化出来。组件也是最核心的抽象,1.0 里的组件,包含了属性,事件,行为三种能力,这点跟 2.0 并无不同。区别在于,没有这么细腻的抽象层次,没有提供只含属性的 Object 抽象。

Module 在 1.0 里面,也是最核心的容器,也承载了对象构建,组件构建和组织的各种工作,本质上实现了 Service Locator 的功能,但是并没有把抽象识别出来。

综述一下,就是 2.0 的核心抽象,比起 1.0 来说,更加的细腻,完整,也更加灵活。但是,比起 1.0 并无实质性的突破,重要的功能 1.0 都提供了。所以,大可不必觉得 1.0 不如 2.0,我觉得在核心抽象层面,只是粗了一点,但是那些细腻真的是必要的么?恐怕也不是。我就看到程序员在实现业务的时候,不分青红皂白继承 Model,完全莫名奇妙的一个做法,可见大部分程序员,在具体实现代码的时候,并不关心核心抽象以及背后的设计思想。这倒也无可厚非,毕竟,使用 PHP 的程序员,有多大概率,能把项目发展到遇到抽象瓶颈的地步呢?