用 yii 框架 10 分钟开发 blog 系统?

date: 2017-10-31 01:19:46
title: 用 yii 框架 10 分钟开发 blog 系统?

因为最近可能工作需要, 又要开始使用 yii 框架. 想想都快 2 年没碰了, 最近一次接触到, 还是整理自己的 wiki, 关于 yii 的内容实在是既乱且杂. 整理的过程中发现自己当时做的笔记实在是 不得要领.

所以写这篇 blog 出来, 结合自己开发 php 框架的经验, 分享一下自己对 php 框架的见解, 希望能帮助到大家.

比较流行也比较重的几个框架(之后的讨论也是基于这几个框架): laravel5 thinkphp5 yii2. 大家在上手这些的框架的时候, 普遍都会感觉有一定的难度. 产生难度的原因, 大致有下面几个:

  • 框架涵盖和解决的问题很多, 需要花一段时间消化
  • 只关注到框架解决问题的快捷, 没有花足够的时间来理解框架的核心
  • 对 MVC 很熟, 却忽视了从框架(或者说请求)的生命周期来进行更全面的理解

我们为什么需要框架

天下武功, 唯快不破

没错, 框架存在的理由, 就是加快开发速度, 增加产出, 把常见的问题给封装掉, 留出更多时间花在 业务 上.

这里简单梳理一下常见问题:

  • 配置管理
  • 日志管理
  • 错误与异常处理
  • 路由 + MVC
  • 数据库服务, 包括关系型数据库, 非关系型数据库
  • 缓存
  • web应用与控制台应用
  • 安全
  • 测试

如果你的技术栈里面连这些基础的问题都没有思考过, 建议你把上面三个框架中的任何一个的文档好好看一遍.

简单过一下这几个问题, 希望能起到抛砖引玉的作用:

  1. 配置管理:
  • 有些内容直接写死到代码里面并不好, 这部分内容多以配置的形式存在
  • 推荐 面向约定 编程, 而不是 面向配置 编程, 比如我们约定类和命名空间的首字母大写, 而不是依赖配置来解决, 尽管不这样写语法上面也没有问题
  • 配置的解析: 最简单的是直接使用 php 数组, 遇到使用 .ini/.yaml 文件的也不要惊讶, 最终还是转化为数组
  • 配置的使用: 直接数组式的访问, 也有 dotenv 形式的访问, 比如 $arr['a']['b']['c'] 的 dotenv 访问类似于 $arr[a.b.c]
  • 不同环境的配置文件管理: 正常项目至少有 2 套环境, 开发环境 + 发布环境, 不同环境下使用的配置文件不同, 为了防止配置文件提交到版本库中对其他环境(其他开发)产生影响, 会设置一些提交策略, 比如 env.php.dev 作为开发环境的配置文件提交, 其他开发获取代码后复制为 env.php 来使用
  1. 日志管理:
  • 日志等级: 要了解标准的日志等级, 实际使用中也至少要使用到 2 个级别 error + info, 前者需要马上处理, 后者方便后期定位问题
  • 日志格式: 方便后期处理与查看
  • 日志存储: 目前大部分直接存到项目的 log 目录, 单文件? 是否需要清理? 日志归集?
  • 怎么打日志, 该打哪些内容到日志里面, 需要经验的积累, 建议新手在可能出现不同结果的代码处, 尝试加一下日志
  1. 错误与异常处理
  • 错误处理的三种方式: C语言式的 return code; 设置错误变量, 比如 json_last_error(); 异常 Exception
  • 现在 php7 已经统一内部的错误处理机制到 抛异常
  • 错误与异常处理往往都需要配合日志一起使用
  • 最外层嵌套一层 try-catch 来捕获异常的方式, 现在也很流行
  1. 路由 + MVC:
  • MVC, 这个还用多说么, 不知道的赶紧恶补
  • 路由的好处也很明显, 抽离出了一部分 http 协议的内容处理掉了, 比如解析 url 信息进行资源定位, http method
  • router 和 controller 之间, 现在流行增加一层, laravel 中称之为 middleware(中间件), yii 称之为 filter(过滤器), 这个后面还会说到
  1. 数据库服务(mysql)
  • mysql 数据库相关的扩展, mysqli 和 pdo, 如果不清楚二者的区别, 甚至不知道扩展(ext), 恶补去吧
  • 框架层做的基础部分: 数据库单例(至少要能手写单例模式)与 mysql 连接(连接 mysql 需要 mysql 协议);
  • 框架层的高级部分: 执行原生 sql; db query build, 查询构造器, 一般采用链式调用; Active Record, 用 model 绑定数据中的表
  1. 数据库服务(nosql)
  • nosql 现在 mongo 还是用的多, 现在的框架想要添加一个外部服务简直不要太简单(这个后面会讲到)
  1. 缓存
  • memcache 和 redis 之争就不赘述了, 不过如果有人用这个问题来考你, 建议你先看看对方并发量再考虑是否要回答这个 深入点 的问题
  • redis 被称之为 程序员的瑞士军刀, 也很适合用来多了解一下 数据结构
  • TTL(time to live) / expiry, 缓存过期更新的问题
  • 缓存是显著提高系统性能的常用手段, 建议仔细阅读框架这部分的文档, 比如你可以在 yii 中看到 http 缓存
  1. web应用与控制台应用
  • 这两个概念不清楚的话, 恶补吧
  • 控制台应用与 crontab, 不知道就百度 crontab, 有兴趣也可以了解一下命令行应用的 argument 和 option, 了解一下 linux shell 的基本原理
  • 如果区分不出来 php-cli 和 php-cgi/php-fpm, 恶补吧
  1. 安全
  • 不用你刻意去学, 框架设计者在写框架之前就需要考虑到, 所以, 去阅读框架的文档吧
  • 密码等信息不能明文存储, 顺便八一八 password_hash() 这个函数, 可以折腾一下下面的代码
public static function hash($str)
{
    $hash = password_hash($str, PASSWORD_DEFAULT);
    return str_replace('$2y$', '$2a$', $hash); // compatible with bcrypt of nodejs
}
  1. 测试
  • TDD, 测试驱动开发, 写代码要有 测试先行 的理念, 推荐 <修改软件的艺术>, 可以培养一下这方面的意识
  • phpunit 可以用起来了, 推荐 unit test 进行函数/方法级别的测试, feature test 进行 api 级别的测试
  • 提到 api, 顺便推荐一下 swagger UI, 简单够用的 api 文档工具

框架之心

框架的核心是什么: 服务容器

这个词如果大家看完 laravel 的文档, 就会有很深的印象了, 这些框架的部分难点, 也在于理解这个概念上. 我尝试解释一下这个, 希望对大家有帮助.

  • 正式些的解释: 服务容器通过依赖注入(DI), 实现控制反转(IoC).
  • 说人话: 不用使用 new

直接看代码:

// 没有服务容器
class Superman
{
    protected $power;

    public function __construct()
    {
        $this->power = new Power(999, 100);
    }
}

// 有服务容器
class Superman
{
    protected $power;

    public function __construct(Power $power)
    {
        $this->power = $power;
    }
}

但是, 需要 new 一个对象这件事不可能凭空消失吧, 没错, 服务容器就是帮我们干了这件事. 如果大家对对象的理解更深一点的话, 服务也可以抽象成对象来实现, 所以, 上面那句:

框架需要添加一个外部服务简直不要太简单

好了, 划了重点了, 下去记吧.

还是来看看代码实现, 来自我之前 blog - 聊一聊 php 代码提示, 这里使用的 hyperframework 框架, 框架核心也是服务容器:

// lib/Services/Redis.php 文件
<?php
namespace App\Services;

use Hyperframework\Common\Config;
use Hyperframework\Common\Registry;

class Redis
{
    /**
     * 将 redis 注册到 Hyperframework 的容器中
     */
    public static function getEngine()
    {
        return Registry::get('services.redis', function () {
            $redis = new \Redis();
            $redis->connect(
                Config::getString('redis.host'),
                Config::getString('redis.port'),
                Config::getString('redis.expire')
            );
            $redisPwd = Config::getString('redis.pwd');
            if ($redisPwd !== null) {
                $redis->auth($redisPwd);
            }
            return $redis;
        });
    }
...
}

建议阅读 laravel官方文档 - container 加深理解.

强烈推荐 学院君 - 深入理解控制反转(IoC)和依赖注入(DI), 写得太好了, 为学院君疯狂打 call.

框架(请求)的生命周期

我们需要故事

如果看过 <人类简史> 这本书, 人类的第一次革命是 认知革命, 简单说就是 讲故事. <用数据讲故事> 这本书也提到, 故事是最容易也最快让人接受的方式.

关于框架生命周期的故事:

  • 起点是入口脚本 index.php, 这里会 new 一个 app 对象, 我们的框架核心, 也就是服务容器
  • 服务容器调用 router 模块, 用来解析 url 里的路由信息, 用来找到对应 controller 中的 action
  • 在 router 和 controller 之间, 可以使用 middleware(或者 filter), 来分离一些业务, 比如维护模式(所有请求直接跳转到 503 页面), 比如开启 session
  • 好了, 我们到了 controller 里啦, controller 会有 2 个属性, Request 和 Response, 分别用来对应 http 的 request 和 response
  • 如果业务涉及到数据(比如数据库), controller 通常找 model 来处理
  • 当然, 展示给用户该怎么处理, controller 也不用关心, 它只需要提供数据给 view 就行了
  • 如果还需要其他服务, 比如 redis, 服务容器很轻松就能解决

这里忽略了很多细节, 大家在看文档或者阅读的源码的过程中, 可以慢慢填充. 这里留一个常见的面试题, 大家可以试试讲故事的方法:

说一下从浏览器输入 url 到看页面发生了什么事, 越详细越好.

我的面试要求是至少要答出来 tcp/ip 4 层网络模型, dns, nginx + fpm 工作模式.

10 分钟?

stay hungry stay foolish

回到标题, 大家平时可能也看到这样的标题, 比如 <使用 laravel 10 分钟搭建博客系统>, <21 天精通 xxx>, 也可能听过或者自己实践过得出 xxx都是骗人的 这样的结论. 首先, 我明确一下, 我是明确支持 用 yii 10分钟搭建博客系统, 下面是具体操作步骤:

  • 感谢魏曦大大的 视频教程, 视频质量高到超乎我的想象, 同样, 为魏曦大大疯狂打 call, 这次博客系统使用教程提供的源码
  • 使用 coding 的动态 page 服务, 按照页面提示配置即可, 期间最耗时的任务是用 phpadmin 使用 sql 文件导入数据

没错, 到这里就结束了, 整个过程 10 分钟绰绰有余.

我是这样来看待的, 或者说这也算我对技术的一大认知:

哪怕只是配置一下域名到服务器, 新手从申请域名, 到配置时理解 A 记录和 CNAME 记录, 都不止 10 分钟, 但这只是我们上一步配置项里面的一个可选项而已. 技术其实就是由这样以及那样, 许许多多的知识点组成的, 了解的更多(基础打扎实), 越会讲故事(构建出自己技术栈和技能图谱), 最终就是能实现这样一个目标, 准确说, 小目标.

一点个人见解

为什么 view 要这么重?

看 yii 框架, 很容易会得出这样一个感受, 特别是你发现 view 界面居然可以只有 php 代码. 为此, yii 框架里面有很多组件库, 帮助达到这样一个效果.

不只是 yii 框架, 其他框架也在这方面做了很多努力, 比如 laravel 的 blade 模板引擎和全套的前端编译构建环境.

我不反对做一个全栈工程师, 但是我的选择是优先做一个更好的 php 工程师. view 层的加重, 更多的是在分散注意力.

前后端分离: 也许我们需要的是一个前端, 最好还是一个妹子.

另外, 我也有个倡议, 不要再叫 老程序员 了.

虽然我们普遍看起来偏老, 但是用长者或者大大是否更好一点?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容