Yii2框架是一个很是庞大可是并不臃肿的 php 框架。使用 Yii2 框架,能够极大的提高开发效率。 秉持着要知其然也要知其因此然的思想,花了一周的时间,看了 linuor 的 《深刻理解Yii2.0》 根据个人理解梳理了一下 Yii2 框架的总体结构。此后简称框架。php
Yii 框架基础
此框架的三个基础概念:程序员
- 属性
- 事件
- 行为
毕竟三生万物。web
属性
一看到这个词可能很迷惑,那么什么是属性呢。 好比说,你如今正在玩一款角色扮演的游戏,角色双手分别有一把 十方大剑
,一个 十方盾牌
。 那么从面向对象的角度而言,你的角色类须要有 左手武器
和 右手武器
两个成员变量。 而且角色类能够从 左手武器
和 右手武器
中得到 力量属性。数据库
这么一说属性这一律念,就很容易理解了。设计模式
事件
仍是以角色扮演游戏为例(这里要对不起不玩游戏的朋友了,原谅我匮乏的想象力,或者你有好的比喻也能够跟我说),游戏里面都有任务系统,而任务会分为主线任务和支线任务,在作主线任务是一般会触发一系列的支线任务。这些支线任务的触发就能够认为是一系列的事件。网络
行为
框架的行为也可使用角色扮演游戏来举例,你在 无尽荒原 捡到了一本魔法书,学会了禁咒魔法,召唤神龙
。 因而你把程序一改,给你的类加一个召唤魔法的方法,这是不可能的。咱们必须让你的类拥有一个动态添加方法的功能,因而全部拿到魔法书的人或者限定职业的人,都能学会这个禁咒,这就是 行为
的做用,动态给类增长方法。架构
以上,有了这三个 框架 实现的武器,咱们才能更快速和灵活的搭建上层的程序。框架
设计模式
依赖注入
框架采用了如今世面上面最多见的一种模式, MVC 模式,具体细节再也不阐述,如今网上关于 MVC 的介绍能够说是烂大街了。 MVC 只是一种大框架上的设计模式,其核心思想是分层,最终目的是解耦。框架在 MVC 的基础上,应用了不少经典的设计模式以及后来发展的设计模式。yii
其中最重要的就是:this
- 依赖注入
- 服务定位器。
那么什么是依赖注入呢 先来一段没有依赖注入的代码:
<?php // 这段代码将 db1 中的t1表的数据备份到 db2 库的 t2 中。 // 所使用的变量都在逻辑过程当中申请。 class Archive { public function doArchive() { $dataDB = new DB1(); $data = $dataDB->query("select * from t1"); $backDB = new DB2(); foreach ($data as $key => $value) { $backDB->query("insert into t2 values ". implode(',', $value)); } die("备份完成"); } }
那么若是再来一个需求,让你把 db3 的数据备份到 db4 中,逻辑相同,那么你该怎么办呢? 有道友就说了,那还不简单, copy & paste,搞定。 因而,你多了一个方法或者一个类。 一直到你的方法和类增长到10个以上时,你都不会有什么感受。 直到产品说如今需求变了,让你把全部的备份库都改为 db3,那么,你就要把手头的工做都停下来,而后将代码中的备份库全改为 db3。
并且,若是你使用的是静态语言,那么,你就要把代码再从新编译一遍。关于静态语言的编译时长:为何c编译须要这么长时间
那么就有了下面这种:
class ArchiveNew { private $originDb; private $backDb; public function doArchive() { $dataDB = new $this->originDb(); $data = $dataDB->query("select * from t1"); $backDB = new $this->backDb(); foreach ($data as $key => $value) { $backDB->query("insert into t2 values ". implode(',', $value)); } die("备份完成"); } /** * @param mixed $originDb */ public function setOriginDb($originDb) { $this->originDb = $originDb; } /** * @param mixed $backDb */ public function setBackDb($backDb) { $this->backDb = $backDb; } }
这个方法,把全部的须要用到的数据库都放到了外面来进行管理,那么咱们称这几个数据库为依赖,称在外部设置数据库的行为为依赖注入。 这只是一种很原始的使用方式,你能够继续延伸,将外部依赖放到统一的地方去管理,那么就有了注入容器(di Container)
服务定位器
服务定位器像是一个注册中心,向服务定位器中注册一个 a 服务,可使用 a 这个名字从服务定位器中取出这个服务。
$locator = new ServiceLocator; $locator->set('a'); $locator->get('a');
服务定位器是基于依赖注入的,在获取服务时,其实会在容器中先注册一个服务。
请求与响应
这一节其实主要讲的就是请求。 请求的内容会比较多,还涉及到网络协议等知识,这里再也不展开。 列举一下重要的几点:
- 路由美化 (将原始的路由修改为比较美观的地址,见导图 请求部分)
- url 解析(将美化过的路由解析成原始请求)
- 请求管理 (包括请求头部,请求体,解析器等等)
数据库
虽然这张图有些搞笑,可是无疑说明了 数据库(MySQL)对于 PHP 的重要性。
类型转换
框架为了兼容各类数据库,对数据类型作了多层封装,而且作了一系列的转换规则:
事务
框架支持事务嵌套,可是嵌套的事务必须成对出现(注意!!!)。 看到事务这一节的时候,正巧同事出了一个 bug ,在脚本的循环中,出错以后没有 commit 或者 rollback ,致使,接下来的生成的事务都成了这个事务的子事务。而框架的嵌套事务,其实是使用代码模拟的,若是父事务没有提交,那么子事务永远不会提交。
事件
const EVENT_INIT = 'init'; // 初始化对象时触发 const EVENT_AFTER_FIND = 'afterFind'; // 执行查询结束时触发 const EVENT_BEFORE_INSERT = 'beforeInsert'; // 插入结束时触发 const EVENT_AFTER_INSERT = 'afterInsert'; // 插入以前触发 const EVENT_BEFORE_UPDATE = 'beforeUpdate'; // 更新记录前触发 const EVENT_AFTER_UPDATE = 'afterUpdate'; // 更新记录后触发 const EVENT_BEFORE_DELETE = 'beforeDelete'; // 删除记录前触发 const EVENT_AFTER_DELETE = 'afterDelete'; // 删除记录后触发
这些事件和其余事件没有什么分别,都是在特定的时候会执行,就不一一阐述了。
乐观锁和悲观锁
框架自带了乐观锁的实现,若是有相似需求,能够在重载yii\db\ActiveRecord::optimisticLock() 方法,返回数据库中的版本号字段便可。在更新与删除时,框架会作相应的操做,来保证,更新的数据是本身拿到的数据,而不是被别人给修改过了。 由于悲观锁不适用于 web 应用,因此框架并无实现悲观锁。
总结
Yii2 框架的总体架构要比 1 版本提高了一个逼格。而且得益于 namespace 特性,框架的目录结构清晰了不少。 对于不想了解框架底层实现的程序员,能够仅仅了解基本使用,就能够上手写业务代码,而不会影响你的开发效率。 只有当你碰见一个很蛋疼的框架内部报错或者 bug 的时候,你才会想到,我去,这怎么这么蛋疼,怎么框架还会有 bug ,可是不少时候是环境、配置或者特定的代码致使的。若是不了解框架的内部逻辑,这个报错或者 bug 会耽误你很长时间。