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);

實際上你經過:json

$model->name = 'grayVTouch';

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

而經過 模型關聯 你卻能夠爲 relation 數組新增單元!this

看到上面的數組合並方式,能夠知道 relation 會覆蓋掉 attribute 中的同名屬性!!於是要特別注意:若是 relation 中有和 attribute 中同名的屬性,請修改 relation 關聯名稱!若是不想修改 relation 名稱,堅持前者覆蓋後者,請:code

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

綜合評價

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

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

相關文章
相關標籤/搜索