yii2開發中19條推薦實踐(阿北總結)

阿北哥ya發表於2018-06-02

雖然每個人的程式設計風格不同,但是有些建議能讓你的程式碼更加規範和穩定,本次就我這次網站更新總結如下幾點,希望對你的yii2學習和使用有所幫助。

環境說明

  • 伺服器環境: 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'
複製程式碼

靜態快取問題

在用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
複製程式碼

具體關於urlManager的配置及常用web伺服器配置可以看下我之前寫的速查表,有現成的程式碼。

小結

一不小心寫了這麼多,當然yii2開發要注意的地方何止這些,以後慢慢說。

相關文章