Yii项目开发总结
学习Yii很久了,一直做的是小案例,自以为学的还不错。直到最近用Yii开发了一个非常简单的CMS,一路下来,磕磕绊绊,才知自己不足。加上最近正学习着偏架构方面的知识。特此总结一下。小白经验,大神轻拍,欢迎讨论。
本篇文章主要是将一些 MVC 代码组织的技巧,不会涉及详细编码。声明使用的模版是Yii高级模板。
痛苦的开发。
所有的php框架几乎都遵循MVC模式设计,网络各种教程、官方手册,也是一股脑的说着按着MVC组织代码。
先说说开发中我的悲惨历史。
大家都知道,在Yii中,一张表对应一个AR,再对应一个控制器。
在开发开始的时候确实是不错的。比如留言功能里面。我在common\models下生成了对应的AR类。然后在frontend和backend的控制器里导入了这个AR类,修改相应视图。然后根据需要对查询做了简单封装,即是在生成的AR类中写了一些方法,然后控制器调用。功能实现,代码逻辑也清晰。自觉棒棒哒。
然后就到痛苦的时候了。在设计文章和栏目的时候,我分了三张表:文章表,栏目表,文章内容表。在common\models生成三个AR类,后台、前台分别调用。由于创建文章时三张表都需要同时用到,以及插入、修改、删除的时候,需要用事务保证一致性。于是我只能就在文章的控制器里添加了一个又一个涉及数据库操作的方法。然后在前台显示的时候,又在对应的模型类里添加了一些方法,前台控制器又是一般修改。首页显示的控制器,映入了八个AR类。然后到最后,看着控制器里一个个AR查询的方法,AR类中又是一堆不同的查询方法,我彻底懵逼了。
好不容易实现完功能,自己都不敢看自己的代码了。
MVC中M的思考
开发完之后,痛定思痛。在大量阅读博客、书籍之下。获得以下经验,与君共享。
关于MVC中,首先声明的一点是设计要“胖Model痩Controller”,即Controller应该只有薄薄的一层。主要业务逻辑都在Model中。
视图层和控制层不用多谈,大家都知道。主要该谈谈的是模型层。
模型中前后台的组织
对于前后都要用到的模型,大家都会生成AR类到common\models,然后在frontend和backend的控制器里导入了这些AR类。但是,这不是一个好的习惯。前后台有着不同的应用逻辑。引用同一个AR类必然职责不清。正确的做法是在前后台的models文件夹里,新建不同的类,然后继承common\models中的AR类,做到模型分离。
举个例子。在common\models中有个Post.phpAR类,你应该在backend\models中新建一个Post.php然后继承common\models中的Post.php类。前台也是如此,做到引用分离。
业务逻辑层(service)
开发中必定涉及到多表关联。如果全部在控制器中引入模型类,写查询语句,代码组织就会非常糟糕,不利于维护管理,更正确的做法是。建立一个业务逻辑层(service)。
也就是做backend和frontend文件夹下建立一个services文件夹,保存我们的业务逻辑。比如我前面有三张表:文章表,栏目表,文章内容表,分别对应三个模型。当我需要保存一片文章时,同时涉及到三张表的操作。我就可以建立一个PostService.php,里面引入这三个AR类,然后建立一个SavePost()方法,在方法里同时对三张表做操作。这样,控制器里只需引入这个服务类,调用相应方法就行了。
读写分离。
实际的应用都是读多写少,因此,我们可以做到代码层面的读写分离。(详细的可以了解了解CQRS架构),方便分别优化。而且Yii中的AR虽然很方便,但是效率不高,太复杂的查询也是不好实现的。
这里Yii提供了一个简单高效的SQL查询。那就是DAO。
就是使用方式是这个的东西。
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
->bindValue(':id', $_GET['id'])
->bindValue(':status', 1)
->queryOne();
我们可以在services文件夹里建立只提供查询的文件,比如PostQuery.php文件提供对文章的查询
总结
第一次开发一个完整的东西,学习到了很多。最近打算对这个CMS进行重构。道路阻且长,加油!


写的不错!我也是刚刚学习,交流下经验。对于model层,我一般都是放在common中,但是为了防止混淆,我会建立表单模型,譬如:Post.php,我会让它对应一个PostForm.php(继承自Model),让它处理业务逻辑,Post.php仅仅处理简单的数据操作或者完全就是一个数据模型。如果,按照楼主的方法,虽然前后端代码分离的更加清晰,但是我想这样做代码是不是会有很多重复了。。毕竟,模型层的操作会有很多一样的。
共 1 条回复
bubifengyun 评论于 2016-12-02 13:26举报相当不错。我的也是都放在
common/models只有特殊的才放在 各自frontend或backend文件夹下。都没有考虑过继承。

huangboyii 评论于 2016-12-12 14:17举报AR模型虽然效率低一些,但是有更多的高级功能。比如事件,行为,事务等等。拿写操作来说,AR模型中提供beforeSave, afterSave这这两个方法,这两个方法会触发相应的事件,你可以在这些事件上绑定一些事件处理器完成对写流程的控制或者完成额外的一些操作,这是Yii2操作数据库最为高级的方式,也是最精华的优点之一。个人以为,牺牲点运行性能,增加开发和理解上的便利性是划算的。
共 2 条回复
不好意思,是我没有表述清楚。我说的是代码层面的读写分离。并不是全用 SQL 语句。
数据库操作就涉及增、删、改、查,其中增、删、改都是会对数据库的内容的状态造成改变,而查操作是不会对数据产生修改的。
针对这个特性,我们可以在代码层面做出读(即查)写(即增、删、改)分离。便于针对不同的优化。
我提出的是,写操作使用 AR 模型,读操作则直接用 SQL 语句。
原因有这么几点:
- 一般的应用中80%是读,20%是写,或者更高。AR 效率低,用来做读性能消耗太大。
- 使用 AR 做读的话,全部采用面向对象的方式,一些复杂的查询不宜实现。
- 其次使用 AR 做读,你并不了解最终生成的 SQL 是什么样的。检测到一些SQL语句执行过慢时,AR 中不好优化。
其实究根结底,最终还是为了性能和维护。
huangboyii 评论于 2016-12-20 09:26回复我认为你的观点——使用AR模型做写操作,而用SQL做读操作非常有道理。Yii的读操作也是分为几个层次,原生态上SQL,DAO和AR模型。DAO的方式读,也提供了Query和BuildQuery帮你生成复杂的SQL语句,但是执行的方式几乎还是和PDO一样,所以效率高的同时,方便性也得到保障。
Yii项目开发总结的更多相关文章
- yii项目开发配置
Clone项目 git clone https://gitee.com/s***/dianshang.git 安装yii php ini 选择 [0] Development 安装扩展 copy co ...
- yii项目开发项目常用技巧和方法汇总
1.使用CActiveForm类组件如何输出不带html属性的结果 eg:<?php echo $form->textField($model,'email',array('size'=& ...
- YII框架开发一个项目的通用目录结构
YII框架开发一个项目的通用目录结构: 3 testdrive/ 4 index.php Web 应用入口脚本文件 5 assets/ 包含公开的资源文件 6 css/ 包含 CSS 文件 7 ima ...
- MVC模式学习--雇员管理系统项目开发
1, 项目开发,使用原型开发, ① 开发流程: 需求分析->设计阶段->编码阶段->测试阶段->发布阶段/维护阶段 需求阶段:PM/项目经理 对客户 设计阶段:技术人员(架构师 ...
- Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录
一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...
- HTML+CSS项目开发总结
好几天没更新博客了,刚实战完一个HTML+CSS的简单项目.经过几天的摸索,发现收益良多.之前只是单纯得写demo,看知识点,没有亲自实战项目.但实战过后才会了解,如何才能更好地提升自己的技术.针对这 ...
- 简历生成平台项目开发-STEP2问卷调查结果统计分析
根据之前设计的调查问卷,截止目前为止,一共收到64份问卷结果.一共16题,分别从基本信息.是否对简历制作有需要.对产品期望的特点和建议采纳四个方面设计问题.下面逐题分析问卷结果: 1.您的性别 可以看 ...
- 如何使用Worktile进行敏捷项目开发管理
Worktile在任务管理上采用了看板视图,非常适合进行敏捷项目开发管理.事实上,在开发Worktile的过程中,我们也是自产自销,使用Worktile管理Worktile本身的开发过程,在本文中跟大 ...
- Java进击C#——项目开发环境
本章简言 上一章我们了解一下开发环境,知道了什么去新建一个项目工程.却并没有去项目工程进行介绍.可是之后我们会常常跟项目工程打交道.所以这章笔者就对项程工程的常用的一些功能进行讲解.当然说全面那是不可 ...
随机推荐
- 将新浪博客里的表情包存入MySQL数据库不完整版本一堆可能用到的散乱代码
header = {'Cookie': 'SINAGLOBAL=7368591819178.463.1491810091070; ALF=1558832450; SCF=Ajrc1sxuwynVIu_ ...
- 侯捷 c++面向对象程序设计
基础知识 基于对象:Object Based 面对的是单一class的设计. 面向对象:Object Oriented 面对的是多重classes的设计,涉及到类和类之间的关系. 课程中设计到两种不同 ...
- 《Effective C++(第三版)》-笔记
1. 让自己习惯C++ 条款01: 视C++为一个语言联邦 1.1 C++ 是一个多重泛型编程语言(multiparadigm programming),支持:过程形式(procedural),面向对 ...
- JavaScript数据类型的检测
主要有一下四种方法: 1.typeof 2.instanceof 3.constructor 4.Object.prototype.toString.call() 1.typeof 不能具体细分是什么 ...
- python‘s third day for me 字符串方法
基 础 数 据 类 型 初 始 int 运算.+ - * / ** %... bool: 判断,真假,作为条件. str: 存储少量的数据.操作简单,便于传输. list: 列表[ ...
- Image与Bitmap的区别及相互转换
1. Image.FromFile()返回的是某个继承自Image的具体类的对象,在这里,就是Bitmap或者Metafile其中之一.这应该算是factory pattern的一种形式.所以,Ima ...
- 用C#操作IO端口1-用并口控制发光二极管
什么是端口? 端口包含了一系列信号线, 通过这个端口CPU可以同其他外部设备交换数据, 比如我们经常见到的Modem,打印机等. 通常情况下, 打开的信号是”1”, 关闭的信号是”0”. 并口在同一时 ...
- **__new__和__init__
这个__new__之前在写单例模式的时候用到过,下面做个深入了解吧. __new__是一个静态方法,而__init__是一个实例方法. __new__方法会返回一个创建的实例,而__init__什么都 ...
- rtmp连接服务器失败(一个低级错误)
由于rtmp底层使用的也是socket ,所以如果想正常使用RTMP_Connect(); 则需要在使用该连接之前先初始化套接字: WORD wVersionRequested; WSADATA ws ...
- 3DMAX导出FBX的烘焙动画选项
勾选了 [烘焙动画]选项时,表示由骨骼动画塌陷为逐帧动画,这样的结果就是:导出的动画确保是正确的,但体积增大,这是骨骼动画与逐帧去画的区别所在. 如果不勾选此选项,则导出的是骨骼动画,可能出现一些问题 ...