天天看點

[PHP]Yii2架構的坑

[PHP]Yii2架構的坑

Yii2是一款優秀的通用Web後端架構,結構簡單優雅、實用功能豐富、擴充性強、性能搞是他最突出的優點。它優秀的地方你在使用過程中總能輕易的發現,無須贅述。而這些隐蔽的小瑕疵,顯得更有必要告訴大家。

[PHP]Yii2架構的坑.md—/Users/zjh/Documents/我的文章/[PHP]Yii2架構的坑

Yii2架構的幾個隐蔽的坑

摘要:Yii2是一款優秀的通用Web後端架構,結構簡單優雅、實用功能豐富、擴充性強、性能搞是他最突出的優點。它優秀的地方你在使用過程中總能輕易的發現,無須贅述。而這些隐蔽的小瑕疵,顯得更有必要告訴大家。

  • 部落格: http://www.cnblogs.com/jhzhu
  • 郵箱: [email protected]
  • 作者: 知明是以
  • 時間: 2015-08-17

目錄

    • 說點閑話
    • ActiveRecord被莫名寫入?
      • 準備知識
      • 代碼現場
      • 總結問題
      • 解決方法
    • 你的Transaction生效了嗎?
      • 問題總結
    • 'Y-m-d'不被識别?

距離上次寫部落格,已經有三個月了。在動手寫之前,總是帶着深深的罪惡感。被它折磨許久,終于,還是,動手了。

值得慶祝的一件事:最近開始,每天早上8:30起來健身了。有兩個視訊很好用,隻需8分鐘,照着做一遍保證你(生)爽(不)到(如)爆(死)。(8分鐘腹肌鍛煉第2級-下載下傳,8分鐘胸肌鍛煉第2級-下載下傳)

值得反思的一件事:最近看了《叔本華美學随筆》,改變了我一直以來對閱讀的看法。我曾經以為閱讀是進步的源動力,卻被這本書深深的打臉了。來,先給大家分享一段:

我們隻管所見的外在環境并不像閱讀物那樣,把某已确定的見解強加給我們的頭腦,而隻是為我們提供了素材和機會。去思考與我們的頭腦能力相稱、與當下的情緒相符的事情。是以,太多的閱讀會是我們的精神失去彈性,就像把一重物持續壓在一條彈簧上面就會是彈簧失去彈性一樣;而讓自己沒有自己思想的最穩妥的辦法就是在空閑的每一分鐘馬上随手拿起一本書。

思考才是進步的源動力!

好了,扯淡完畢,步入正題。

  1. ActiveRecord

    的基本用法。如果不了解,可參考這裡。

/**
 * @property integer $id
 * @property string $name
 * @property string $detail
 * @property double $price
 * @property integer $area
 **/
class OcRoom extends ActivieRecord
{
    ...
}

$room = OcRoom::find()      //先取出一個對象。
    ->select(['id'])        //隻取出'id'列
    ->where(['id'=>20])
    ->one();
$room->save();              //儲存,會發現此行的其它字段都被寫成預設值了。
      

這個例子的問題在于:

  1. 我從資料庫中取出了一行,也就是代碼中的

    $room

    ,但是隻取出了

    id

    字段,而其他字段自然就是預設值。
  2. 當我

    $room->save()

    的時候,那些是預設值的字段也被儲存到資料庫裡去了。what!?
  3. 也就是說,當你想節約資源,不取出所有字段的時候,一定要注意不能儲存,否則,很多資料會被莫名修改為預設值。

然而,我們有什麼解決辦法呢?提供幾種思路:

  1. 自己時刻注意,避免未完全取出的

    ActiveRecord

    的儲存。
  2. 修改或繼承

    ActiveRecord

    , 使得,當此對象由

    find()

    建立,且字段沒有完全取出,調用

    save()

    方法,抛出異常。
  3. ActiveRecord

    ,使得,當此對象由

    find()

    save()

    方法時,隻儲存取出過的字段,其他字段被忽略。

/**
 * @property integer $id
 * @property string $name
 **/
class OcRoom extends ActiveRecord
{
    public function rules()
    {
        return [['name','string','min'=>2,'max'=>10]];
    }
    ...
}
class OcHouse extends ActiveRecord
{
    public function rules()
    {
        return [['name','string','max'=>10]];
    }
    ...
}

$a = new OcRoom();
$a->name = '';                //name為空字元串,不滿足rules()條件。

$b = new OcHouse();
$b->name = '我的房間';         //name合法,可以儲存。

$transaction = Yii::$app->db->beginTransaction();
try{
    $a->save();               //name字段不合法,無法驗證通過,在validate()階段已經傳回false,不會進行資料庫存儲的步驟,是以也不會抛出異常。
    $b->save();               //name字段合法,可以正常儲存。

    $transaction->commit();   //送出後,發現$a儲存失敗,而$b儲存成功。
}
catch (Exception $e) 
{
    Yii::error($e->getTraceAsString(),__METHOD__);
    $transaction->rollBack();
}
      

這段代碼的問題在于:

  1. 大家知道

    $transaction

    的存在意義是保證整段資料庫存儲代碼要麼全成功,要麼全失敗。
  2. 顯然,在這個例子中,

    transaction

    并沒有達到我們想要的效果:

    $a

    因為

    validate()

    都沒過,是以

    $transation->commit()

    的時候并不會報錯。

$transation

塊内,所有的

save()

都要判斷下傳回值,如果為

false

,則直接抛出異常。

OcRenterBill extends ActiveRecord
{
    public function rules()
    {
        return [
            ['start_time','date','format'=>'Y-m-d'],
        ];
    }
}

$a = new OcRenterBill();
$a = '2015-09-12';
$a->save();                 //會報錯,說格式不對。
      

如果一開始,Yii架構就報錯,這個還不算坑。坑的是我在Mac上開發時,這個可以完全正常的工作,而釋出到線上環境(Ubuntu)後,就彈出“屬性start_time格式無效”的錯誤。而參考官方文檔,發現這種格式是允許的官方文檔。

啊啊啊。各種試錯,最後發現如果改成

php:Y-m-d

,世界就清淨了。是以,如果你遇到這種問題,感激我吧。

此部落格已遷移至blog.bookbook.in,以後不再更新