Laravel 框架 Model 對象轉 json 字符串丟失更新

場景還原

UserModel

class UserModel extends Model {
    public function role()
    {
        return $this->belognsTo(RoleModel::class , 'role_id' , 'id');
    }
}

出錯的程序

$user = UserModel::with('role')->find(1);
// $user->role 是一個 RoleModel
// 更新 role 屬性
$user->role = 'test';
// 正確輸出 test
var_dump($user->role);
// 但是!!轉換成 json 字符串後
// 你會發現,role 居然還是個模型!!
// 並不是你後面設置成的 test !
// 怪胎,丟失更新了?Laravel Bug ??
// 實際上不是!請看下屬描述
var_dump(json_encode($user));

原理概述

LaravelIlluminate\Database\Eloquent\Model 實現了 JsonSerializable 接口,所以在調用 json_encode 進行序列化時,會調用 Model::jsonSerialize 方法,他這個方法返回的數據是:

array_merge($attribute , $relation);

實際上你通過:

$model->name = 'grayVTouch';

這種方式附加的新屬性,Laravel 通過 __set 魔術方法重載,將其添加到 attribute 數組中,你是無法更改 relation 數組的!

而通過 模型關聯 你卻可以爲 relation 數組新增單元!

看到上面的數組合並方式,可以知道 relation 會覆蓋掉 attribute 中的同名屬性!!因而要特別注意:如果 relation 中有和 attribute 中同名的屬性,請修改 relation 關聯名稱!如果不想修改 relation 名稱,堅持前者覆蓋後者,請:

// 保存值
$attr = $model->attr;
// 刪除屬性:attribute / relation 中的屬性(Laravel 內部調用 __unset 魔術方法)
unset($model->attr)
// 重新設置值,僅設置到 attribute 數組
// relation 並不會被設置
$model->attr = $model;

綜合評價

Laravel 由於將模型屬性拆分成兩個數組,而他們實際上又同屬於一個對象!所以如果存在同名屬性,必然會產生 誰覆蓋誰 的問題,attribute 一開始就是對應數據庫表中的字段的,而 relation 是後面程序附加的,爲了不丟失更新,後者覆蓋前者,非常正確。

雖然在使用過程中應該小心避免 relationattribute 撞上同名屬性,但偶爾還是會碰到的~,這個還是稍微注意下就好,這並非 Bug,而是在當前的程序處理方式下必然會產生的一個正常現象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章