|
PHP 5.4 全新 trait 语法
文章转载于:http://blog.makingware.com/?p=97
发表于 2011 年 06 月 08 日 由 Jeffrey Au
<!-- .entry-meta -->最近看 PHP 5.4 的 Changelog 时发现新增了 Trait 语法,根据 wiki 的说明,这个语法是为了解决代码的“水平复用”而诞生的。什么是“水平复用”呢?这里用一个相对简单的例子说明一下: 要理解水平复用,必须从 OOP 的 DRY 实践说起……
假设现在有三个业务类,它们都使用 ActiveRecord 模式实现持久化,那么代码看上去会像这样:
view source
print?
4 | class User extends ActiveRecord {} |
5 | class Article extends ActiveRecord {} |
6 | class Log extends ActiveRecord {} |
然后,你发现 User 和 Article 的内容需要经常被读取,为了加快读取速度要用上 Cache,而 Log 大部分时候都是写入,很少读取,不需要使用 Cache。传统方法上,为了实现 Cache 读取,会把代码写成这样:
view source
print?
04 | class User extends ActiveRecord { |
07 | // 判断 Cache 在不在,读 Cache 然后返回 |
10 | class Article extends ActiveRecord { |
13 | // 判断 Cache 在不在,读 Cache 然后返回 |
16 | class Log extends ActiveRecord {} |
这样明显有个问题,User 和 Article 使用 Cache 的代码是重复的!这时你可能想到把可以被 Cache 的类继承到另外一个叫 CachedActiveRecord 里面,把代码写成这样:
view source
print?
3 | class CachedActiveRecord extends ActiveRecord {} |
5 | class User extends CachedActiveRecord {} |
6 | class Article extends CachedActiveRecord {} |
7 | class Log extends ActiveRecord {} |
这样的确解决了重复 Cache 代码的问题,但另外一个问题又来了:如果我要在 User 和 Article 实现不同的 Cache 策略呢?
这种方式只能实现固定的 Cache 策略,虽然可以通过 if..else../switch 来实现,但这样显然不符合 OOP 的原则。
于是有人实现了 Mixin 模式,把需要重用的代码抽到一个独立的类里面,然后令所有类继承都一个 Mixin 工具类,工具类通过 PHP 特有的 __set / __get / __call 等方式把需要重用的类塞到当前类里面,代码会变成这样子:
view source
print?
03 | class ActiveRecord extends Mixin {} |
04 | class CacheBehavior extends Mixin { |
06 | function find($self) { |
11 | class User extends ActiveRecord {} |
12 | class Article extends ActiveRecord {} |
13 | class Log extends ActiveRecord {} |
17 | $user->attach(new CacheBehavior()); |
18 | $user->find(); // 此时调用的是 CacheBehavior 的 find 方法 |
这样貌似解决了代码重用的问题了……且慢!你没发现这样的话所有类都必须继承 Mixin 工具类吗?如果某天需要用上一个不 Mixin 的 ActiveRecord 那岂不是需要把它复制一份?
于是这里就需要 trait 语法的粉墨登场了!先把 CacheBehavior 变成 trait,代码变成这样:
view source
print?
08 | class User extends ActiveRecord { |
11 | class Article extends ActiveRecord { |
14 | class Log extends ActiveRecord {} |
这样就实现了刚才使用了 Mixin 工具类才能实现的效果,代码量更少更简洁!
进一步思考,其实 ActiveRecord 也属于工具类而不是业务类(领域模型),那实际上也是应该拿出来的,于是最后代码写成了:
view source
print?
08 | use ActiveRecord, CacheBehavior; |
11 | use ActiveRecord, CacheBehavior; |
19 | $user->find(); // 此时调用的是 CacheBehavior 的 find 方法,省略了 attach 步骤 |
代码终于和谐了!当然,ActiveRecord 和 CacheBehavior 之间的关联性还有待解决,不过这里就不纠结这个问题了=v=b
使用 trait 之后,某天出现了一个新的业务类 Manager 也只需轻松继承或 use 一下即可:
view source
print?
03 | use ActiveRecord, CacheBehavior; |
05 | class Manager extends User {} |
08 | use ActiveRecord, CacheBehavior; |
12 | $manager = new Manager(); |
13 | $manager->find(); // 同样是使用 CacheBehavior 的 find 方法 |
从此对“水平复用”代码表示毫无鸭梨!
更多说明请查看官方 wiki:https://wiki.php.net/rfc/horizontalreuse
<!-- .entry-content --> |
|
|
|
|
|
|