设为首页 收藏本站
查看: 1506|回复: 0

[经验分享] PHP 5.4 全新 trait 语法

[复制链接]

尚未签到

发表于 2017-4-3 11:14:53 | 显示全部楼层 |阅读模式
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?

1// 工具类

2class ActiveRecord {}

3// 业务类

4class User extends ActiveRecord {}

5class Article extends ActiveRecord {}

6class Log extends ActiveRecord {}



  然后,你发现 User 和 Article 的内容需要经常被读取,为了加快读取速度要用上 Cache,而 Log 大部分时候都是写入,很少读取,不需要使用 Cache。传统方法上,为了实现 Cache 读取,会把代码写成这样:
view source
print?

01// 工具类

02class ActiveRecord {}

03// 业务类

04class User extends ActiveRecord {

05    // 重载查询方法

06    function find() {

07        // 判断 Cache 在不在,读 Cache 然后返回

08    }

09}

10class Article extends ActiveRecord {

11    // 重载查询方法

12    function find() {

13        // 判断 Cache 在不在,读 Cache 然后返回

14    }

15}

16class Log extends ActiveRecord {}



  这样明显有个问题,User 和 Article 使用 Cache 的代码是重复的!这时你可能想到把可以被 Cache 的类继承到另外一个叫 CachedActiveRecord 里面,把代码写成这样:
view source
print?

1// 工具类

2class ActiveRecord {}

3class CachedActiveRecord extends ActiveRecord {}

4// 业务类

5class User extends CachedActiveRecord {}

6class Article extends CachedActiveRecord {}

7class Log extends ActiveRecord {}



  这样的确解决了重复 Cache 代码的问题,但另外一个问题又来了:如果我要在 User 和 Article 实现不同的 Cache 策略呢?
这种方式只能实现固定的 Cache 策略,虽然可以通过 if..else../switch 来实现,但这样显然不符合 OOP 的原则。
于是有人实现了 Mixin 模式,把需要重用的代码抽到一个独立的类里面,然后令所有类继承都一个 Mixin 工具类,工具类通过 PHP 特有的 __set / __get / __call 等方式把需要重用的类塞到当前类里面,代码会变成这样子:
view source
print?

01// 工具类

02class Mixin {}

03class ActiveRecord extends Mixin {}

04class CacheBehavior extends Mixin {

05    // 重载源对象的查询方法

06    function find($self) {

07        // 通过传入参数获取原对象实例

08    }

09}

10// 业务类

11class User extends ActiveRecord {}

12class Article extends ActiveRecord {}

13class Log extends ActiveRecord {}

14  

15// 调用方式

16$user = new User();

17$user->attach(new CacheBehavior());

18$user->find(); // 此时调用的是 CacheBehavior 的 find 方法



  这样貌似解决了代码重用的问题了……且慢!你没发现这样的话所有类都必须继承 Mixin 工具类吗?如果某天需要用上一个不 Mixin 的 ActiveRecord 那岂不是需要把它复制一份?
于是这里就需要 trait 语法的粉墨登场了!先把 CacheBehavior 变成 trait,代码变成这样:
view source
print?

01// 工具 trait

02trait CacheBehavior {

03    function find() {}

04}

05// 工具类

06class ActiveRecord {}

07// 业务类

08class User extends ActiveRecord {

09    use CacheBehavior;

10}

11class Article extends ActiveRecord {

12    use CacheBehavior;

13}

14class Log extends ActiveRecord {}



  这样就实现了刚才使用了 Mixin 工具类才能实现的效果,代码量更少更简洁!
进一步思考,其实 ActiveRecord 也属于工具类而不是业务类(领域模型),那实际上也是应该拿出来的,于是最后代码写成了:
view source
print?

01// 工具 trait

02trait ActiveRecord {}

03trait CacheBehavior {

04    function find() {}

05}

06// 业务类

07class User {

08    use ActiveRecord, CacheBehavior;

09}

10class Article {

11    use ActiveRecord, CacheBehavior;

12}

13class Log {

14    use ActiveRecord;

15}

16  

17// 调用方式

18$user = new User();

19$user->find(); // 此时调用的是 CacheBehavior 的 find 方法,省略了 attach 步骤



  代码终于和谐了!当然,ActiveRecord 和 CacheBehavior 之间的关联性还有待解决,不过这里就不纠结这个问题了=v=b
使用 trait 之后,某天出现了一个新的业务类 Manager 也只需轻松继承或 use 一下即可:
view source
print?

01// 这样

02class User {

03    use ActiveRecord, CacheBehavior;

04}

05class Manager extends User {}

06// 或者

07class Manager {

08    use ActiveRecord, CacheBehavior;

09}

10  

11// 直接调用

12$manager = new Manager();

13$manager->find(); // 同样是使用 CacheBehavior 的 find 方法



  从此对“水平复用”代码表示毫无鸭梨!
更多说明请查看官方 wiki:https://wiki.php.net/rfc/horizontalreuse


<!-- .entry-content -->

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-359512-1-1.html 上篇帖子: 基于PHP的cURL快速入门1 下篇帖子: PHP下使用SimpleXML处理XML文件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表