toarray() 输出字段由fields()和extrafields()分层协作决定:fields()定义默认必显字段,extrafields()提供需显式请求的可选扩展字段,同名时后者覆盖前者。

Yii2 的 toArray() 方法输出哪些字段,完全由 fields() 和 extraFields() 共同决定——但它们的职责不重叠,而是分层协作。
fields() 控制默认必显字段
这是 toArray 的“基础输出清单”。只要调用 $model->toArray(),不传任何参数,就只按 fields() 返回的键值映射来生成数组。
- 返回的数组键是响应中的字段名,值可以是属性名(如
'id' => 'id')、匿名函数(用于计算或格式化),甚至省略键直接写字符串(如'name'表示字段名和属性名一致) - 未在
fields()中声明的 public 属性、关联对象、动态属性,一律不会出现,哪怕它们有值 - 常用于剔除敏感字段(如
password_hash)、重命名('email' => 'email_address')、补充计算字段('full_name' => function($m) { return $m->first_name . ' ' . $m->last_name; })
extraFields() 提供可选扩展字段
这些字段不会自动出现在 toArray() 结果里,必须显式请求才加载。典型场景是 API 的 expand 参数。
- 调用
$model->toArray(['*'], ['avatar_url', 'profile'])或$model->toArray([], ['avatar_url']),才会把extraFields()中定义的字段合并进去 - 适合放开销较大、非必需的数据:比如头像 URL(需拼接路径)、完整地址(需关联查询)、统计计数(需额外 SQL)
- 同样支持属性映射和闭包,例如:
'avatar_url' => function($m) { return $m->avatar_path ? '/uploads/' . $m->avatar_path : '/default.png'; }
两者叠加时的优先级与合并逻辑
fields() 是底座,extraFields() 是插件。它们返回的字段名若冲突,extraFields() 中的定义会覆盖 fields() 中同名字段。
- 合并不是简单 array_merge,而是以
fields()为基准,再将extraFields()中请求的键逐个注入 - 如果
fields()返回['id', 'name'],extraFields()返回['name' => 'full_name'],且你调用了toArray([], ['name']),结果中name的值就是full_name对应的内容 - 这种设计让接口既能保持精简默认响应,又能按需加载深度数据,避免 N+1 或过度传输











