雖然每一個人的編程風格不一樣,可是有些建議能讓你的代碼更加規範和穩定,本次就我此次網站更新總結以下幾點,但願對你的yii2學習和使用有所幫助。php
環境說明css
接下來開說html
先說說開發前的事情,磨刀不誤砍柴工,將yii2配置到一個最易開發的狀態。mysql
這個是作yii2開發的基石,除非沒有辦法使用,不然請不要放棄,除了更容易的安裝yii2及第三方擴展外,能使用Composer表明着你的服務器最少能運行起來php-cli,那麼你就可使用yii命令行,它會爲你的開發帶來無盡的遍歷。web
對於composer,有些關鍵詞你要特別關注 install、update、require。sql
默認安裝yii2時,程序的相關信息是英文的,第一步咱們須要改爲中文的,很簡單。數據庫
// config/web.php
'language'=>'zh-CN'
複製代碼
在用yii2的時候,咱們習慣將靜態文件(圖片、css文件、js文件等)放到資源類中管理,可是可能存在瀏覽器緩存問題,在開發階段能夠經過配置來避免這個問題,尤爲是開發移動端頁面的時候特別有用。編程
// config/web.php
'assetManager'=>[
'appendTimestamp' => true
],
複製代碼
雖然yii2對數據庫,尤爲是對mysql是很友好的,可是咱們仍是應該使用穩定高一點的版本,別說你的程序未來沒有移動端,早早的選擇一個支持emoji的數據庫會避免咱們下載第三方庫去解決報錯問題。瀏覽器
若是能夠緩存
若是可能,請配置一個相似於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和場景吧。**一切。
編碼的原則是盡最大努力讓代碼複用,尤爲是小掛件,它讓視圖層實現了複用,小掛件的使用很是簡單
一、在@app下創建一個文件夾components
二、在components內創建一個掛件類(必須繼承yii\base\Widget)
三、渲染一個小掛件的視圖(若是須要,在components/views下)
四、使用它
沒看明白?我給個例子。
// 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等。關於小掛件我以前也寫了一篇文章,有興趣的同窗能夠看看。 傳送門
這個問題我以前也視頻說過,就是惰性加載和即時加載的問題,好比下面的代碼並很差
$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,雖然它可能不少行,可是表意簡潔,你能看懂、他也能看懂。
何苦廢了牛勁去寫一個自我感受巨牛逼的表達式那!!!
在寫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(),
]
];
}
}
複製代碼
所以在數據表中我推薦時間字段命名規則以下
這樣如上代碼就徹底夠用了,無需指定字段。
記住:去掉在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風格的錯誤處理頁面》
嚴格來講這個應該在開發階段作,爲了對搜索引擎更有好,也爲了增長程序的安全性,咱們應該對url進行美化,好比
/index.php?r=admin/user/index // 寫成 /admin/user-index.html
複製代碼
具體關於urlManager的配置及經常使用web服務器配置能夠看下我以前寫的速查表,有現成的代碼。
一不當心寫了這麼多,固然yii2開發要注意的地方何止這些,之後慢慢說。