yii2使用笔记(转)

yii2开发中19条推荐实践(阿北总结)

环境说明

服务器环境: CentOS

开发环境及IDE:mac & phpstorm

Yii:v2.0.15 基础版

接下来开说

开发前

先说说开发前的事情,磨刀不误砍柴工,将yii2配置到一个最易开发的状态。

Composer

这个是做yii2开发的基石,除非没有办法使用,否则请不要放弃,除了更容易的安装yii2及第三方扩展外,能使用Composer代表着你的服务器最少能运行起来php-cli,那么你就可以使用yii命令行,它会为你的开发带来无尽的遍历。

对于composer,有些关键词你要特别关注 install、update、require。

中文化

默认安装yii2时,程序的相关信息是英文的,第一步我们需要改成中文的,很简单。

// config/web.php'language'=>'zh-CN'复制代码

// config/web.php

'language'=>'zh-CN'

静态缓存问题

在用yii2的时候,我们习惯将静态文件(图片、css文件、js文件等)放到资源类中管理,但是可能存在浏览器缓存问题,在开发阶段可以通过配置来避免这个问题,尤其是开发移动端页面的时候特别有用。

// config/web.php

'assetManager'=>[

    'appendTimestamp' => true

],

配置DB

虽然yii2对数据库,尤其是对mysql是很友好的,但是我们还是应该使用稳定高一点的版本,别说你的程序将来没有移动端,早早的选择一个支持emoji的数据库会避免我们下载第三方库去解决报错问题。

如果可以

mysql5.3.3 +

config/db.php 的charset=utf8mb4

配置debug

如果可能,请配置一个类似于xdebug的PHP扩展并且集成到你的IDE中,开发过程中难免遇到不好捕获的bug,这需要你在一个yii2生命周期内持续的观察某些变量的值及赋值路径,具体配置可以参考我之前的课程,用xdebug支持yii2调试之 - PhpStorm配置篇

当然,yii2自己的debug扩展也极其有用,尤其配置urlManager的时候。

开发中

本段为你介绍我在yii2开发中一些习惯和小技巧,希望对你有用。

单一职责

一个类和一个方法应该只有一个职责,比如下面的代码

function getFullName(){

    $isAdmin = Administrator::find()->where(['user_id'=>$this->id])->one();

    if($isAdmin && $this->xxx == 1){

        return $this->first_name . " " . $this->last_name;

    }

}

比如上面的情况我们最好是将对是否为管理员的判断单独提取出来,如下

function getFullName(){


    if($this->isAdmin() && $this->xxx == 1){

        return $this->first_name . " " . $this->last_name;

    }

}

function isAdmin(){

    return Administrator::find()->one();

}

每个方法是一个最小化的问题解决单元,相关知识可以看下《重构 - 既有代码的改善》这本书,北哥大约三年前读过,很多小技巧,受益颇多。

模型的重要性

很多yii2的初学者喜欢将大量逻辑写到控制器的动作(action)中,这是不对的,我们的重点应该在模型中,而控制器仅仅是做输入输出。

我们拿关联举个例子,下面的这段代码是不好的。

// 某个控制器

public function actionIndex(){

    // 这里还有很多代码

    ....


    // 获得三天前的某个会员的订单集合

$order = Order::find()->where(["user_id"=>$userId])->andWhere([">","created_at",strtotime(date("Y-m-d",time()))-86400*3])->all();   

}

我们最好将这段逻辑放到会员模型中

// User模型

public function recent3DaysOrders(){

    return Order::find()->where(["user_id"=>$this->id])->andWhere([">","created_at",strtotime(date("Y-m-d",time()))-86400*3])->all();

}

// 控制器中

public function actionIndex(){

    $order = $user->recent3DaysOrders();

}

控制器的代码力求简单,只做基本的输入帅选以及输出渲染。

规则

对与错,不要随便就写。

// 某个控制器的action中

public function actionCreate(){

    $model = new User();

    if(Yii::$app->request->isPost){

        $model->load(Yii::$app->request->post());

        if($model->xxx == xxxx){

            // todo

        }

        if($model->save()){

            //

        }

    }

}

上面的代码再熟悉不过了,这是我们期望的样子,但是有的时候输入并不会这样老实,我们需要进行更多验证,请不要将验证直接写到action内,比如上面代码中的if判断。

**将验证的工作交给模型的rule和场景吧。**一切。

复用随时要想到(小挂件)

编码的原则是尽最大努力让代码复用,尤其是小挂件,它让视图层实现了复用,小挂件的使用非常简单

1、在@app下建立一个文件夹components

2、在components内建立一个挂件类(必须继承yii\base\Widget)

3、渲染一个小挂件的视图(如果需要,在components/views下)

4、使用它

没看明白?我给个例子。

// components/Top10.php

<?php

namespace app\components;

use yii\base\Widget;

class Top10 extends Widget {

    public function init(){

        parent::init();

    }

    public function run(){

        parent::run();

        return $this->render('top10');

    }

}

写一个视图

// components/views/top10.php

<h1>Hello Top10</h1>

// 某个视图

<?= \app\components\Top10::widget();?>

当然挂件可以很复杂,比如我们使用的ActiveForm、GridView等。关于小挂件我之前也写了一篇文章,有兴趣的同学可以看看。 传送门

AR关联的循环要很小心

这个问题我之前也视频说过,就是惰性加载和即时加载的问题,比如下面的代码并不好

$customers = Customer::find()->limit(100)->all();

foreach ($customers as $customer) {

    // SELECT * FROM `order` WHERE `customer_id` = ...

    $orders = $customer->orders;

}

上面的代码执行了101次查询,如果数据更多那?对于上面的问题我们是这样解决的。

// SELECT * FROM `customer` LIMIT 100;

// SELECT * FROM `orders` WHERE `customer_id` IN (...)

$customers = Customer::find()

    ->with('orders')

    ->limit(100)

    ->all();

foreach ($customers as $customer) {

    // 没有任何的 SQL 执行

    $orders = $customer->orders;

}

从101次查询减少到2次。

让你的代码更加“简洁”

这里说的简洁并不是说代码量,而是表意。比如下面的代码

// 方式1

if($num > 100){

    return 1

}else{

    return 2

}

// 方式2

return $num > 100 ? 1 : 2;

代码逻辑很简单的时候我们都喜欢第二种方式,但是如果逻辑复杂些,我更喜欢方式1,虽然它可能很多行,但是表意简洁,你能看懂、他也能看懂。

何苦废了牛劲去写一个自我感觉巨牛逼的表达式那!!!

为视图的PHP代码增加一个try

在写action或模型方法的时候,为了保证代码的稳定性,我们一般都会用try....catch语法结构,但是在yii2的视图内很少有人用,记住,也要用!比如下面这段代码。

// 视图内

<?= \app\components\WechatLangSideMenu::widget();?>

如果上面代码出错了怎么办,我推荐如下方式写

<?php

try {

    echo \app\components\WechatLangSideMenu::widget();

}catch(\Exception $e){

// 可以不处理也可以写你自己的错误处理。

}

?>

小心使得万年船。

勿写死,用常量或配置。

有些代码需要一些判断,而判断的参考是某些值,比如下面的代码

if($this->type === 1){

    return "文章";

}else if($this->type === 2){

    return "专栏";

}

我推荐这样写

if($this->type === Item::ARTICLE_TYPE){

    return "文章";

}else if($this->type === Item::TOPIC_TYPE){

    return "专栏";

}

ARTICLE_TYPE 和 TOPIC_TYPE是Item模型的两个常量。

使用迁移脚本

我说过了很多次,本篇还是要说一次,对于一个yii2程序的数据库部分请用migration来管理。

并且这些脚本应该一起放到到你的版本控制里,记住,迁移脚本一般包含两个部分。

结构脚本

种子数据的导入

很多人都忽略了第二类。另外在做迁移脚本的时候,如果你的表有前缀,那么在脚本里的写法如下

{{%user}}// discuz_user

时间问题

使用yii2开发mysql类web应用的时候,数据表的时间类字段我们喜欢用时间戳,一般表内都会有记录生成时间和更新时间字段。

对于他们的更新请使用yii2内置的TimestampBehavior行为类,则字段数据的填充我们就无需操心了,如下代码

namespace app\models;

use Yii;

use yii\behaviors\TimestampBehavior;

class Article extends \yii\db\ActiveRecord {


    public function behaviors(){

        return [

            [

                'class' => TimestampBehavior::className(),

            ]

        ];

    }   

}

因此在数据表中我推荐时间字段命名规则如下

生成时间 created_at

更新时间 updated_at

这样如上代码就完全够用了,无需指定字段。

记住:去掉在rules内对created_at和updated_at字段required的限制。

是父类还是行为

其实我是不排斥任何一种的,各有利弊吧,父类使用简单但是增加了耦合,行为耦合度低但是配置比直接父类复杂些。

当然从理念上说也有点不同

行为 一些类附加的属性

父类 一些类共同的属性

我的用法(不一定就是对的),尤其在模块中我喜欢为控制器增加一层父类。

开发完

程序开发完还需要对yii2程序进行一些配置,很多你一定已经会了。

入口文件

我们首先要改变yii2的运行模式,从开发模式变为生产模式,一般代码如下

// index.php

defined('YII_DEBUG') or define('YII_DEBUG', false);

defined('YII_ENV') or define('YII_ENV', 'prod');

报错页面

对于一个稳定的程序,报错不要紧,要紧的是报错后的处理,既然用户觉得有好又对开发人员有帮助,我之前写过一篇文章,你可以看下《用yii2实现youtube风格的错误处理页面》

urlManager

严格来说这个应该在开发阶段做,为了对搜索引擎更有好,也为了增加程序的安全性,我们应该对url进行美化,比如

/index.php?r=admin/user/index // 写成 /admin/user-index.html

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

推荐阅读更多精彩内容

  • awesome-yii2 Yii2 干货集,欢迎点 Watch 订阅,也欢迎提交 Pull Requests。(提...
    guanguans阅读 1,143评论 0 6
  • 安装YII2 在确保composer安装完成后通过composer安装YII2 第一条命令为全局安装一个js的包管...
    某不科学的XX阅读 1,749评论 0 2
  • 我们用实例来说明这一部分 表结构 现在有客户表、订单表、图书表、作者表, 客户表Customer(idcustom...
    神秘者007阅读 1,351评论 0 0
  • date: 2017-11-21 18:15:18title: yii 源码解读 百度脑图 - yii 源码解析:...
    daydaygo阅读 3,416评论 1 11
  • 某晚,搭出租车回家。 司机是个小鲜肉,一边开车一边和一个亲密女人聊天,对方发给他一些搞笑视频,彼此甚是欢乐。 终于...
    蔷薇季阅读 319评论 0 0