You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让通过__set存入$attributes的模型属性返回时正常序列化为JSON?

问题原因

PHP 将对象序列化为 JSON 时,默认仅会输出对象的公共可见属性。你的 $attributes 是 protected 修饰的,且 __get/__set 魔术方法仅在直接访问对象的未定义属性时触发,JSON 序列化过程不会调用这些魔术方法,因此最终得到空对象。

__toString 方法无效的原因是:只有当对象被当作字符串直接使用(比如 echo $object)时才会触发该方法,而将对象放入数组中进行 JSON 编码时,并不会调用它。

解决方案

1. 实现 JsonSerializable 接口(最直接有效)

通过实现 PHP 内置的 JsonSerializable 接口,让对象自己定义 JSON 序列化的内容:

class Model implements JsonSerializable
{
    protected $attributes = [];

    public function __set($key, $val){
        $this->attributes[$key] = $val;
    }

    public function __get($key){
        return $this->attributes[$key] ?? throw new Exception("attribute not found");
    }

    // 定义 JSON 序列化时返回的内容
    public function jsonSerialize()
    {
        return $this->attributes;
    }
}

此时再执行你的测试代码,JSON 编码就会输出 $attributes 中的所有键值对,符合预期。

2. 参考 Laravel Eloquent 的实现思路

Laravel 的 ActiveRecord 模型核心也是通过 JsonSerializable 接口控制序列化输出,同时做了更多封装:

  • 模型的 jsonSerialize 方法会调用 toArray,后者会处理属性的类型转换、隐藏/可见属性过滤、关联模型序列化等逻辑
  • 通过 fillable/guarded 属性限制可批量赋值的字段
  • 封装 getAttribute/setAttribute 方法,在读写属性时自动处理类型转换(比如日期转 Carbon 实例、数组转 JSON 等)

如果想实现类似的 ActiveRecord 风格,可以参考这个思路,逐步扩展属性的读写控制、序列化规则等功能。

内容的提问来源于stack exchange,提问作者Avi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 07:06:32