yii2模型默认实现arrayable接口,可通过重写fields()和extrafields()定制toarray()输出:字段白名单/黑名单、关联数据显式展开、嵌套路径与回调处理;asarray()则绕过模型直接映射数据库字段,两者路径不同。

Yii2 模型默认就实现了 Arrayable 接口(因为 yii\base\Model 和 yii\db\ActiveRecord 都已实现),所以你不需要手动实现它,但你可以重写 toArray() 的行为来精确控制哪些字段、如何嵌套、是否包含关联数据、是否应用过滤逻辑等。
关键点不是“实现接口后行为变化”,而是“重写 toArray() 或相关 Arrayable 方法后,输出结构可被定制”。
以下是实际影响你 API 输出的几个核心变化方向:
-
字段白名单/黑名单控制
重写fields()返回允许导出的字段列表;重写extraFields()定义可选扩展字段(如关联模型、计算属性)。public function fields() { return ['id', 'name', 'email']; // 只暴露这三个字段 } public function extraFields() { return ['profile', 'posts']; // 关联对象需定义 getter 或 relation }调用
$model->toArray(['id', 'name'], ['profile'])时,才会包含profile数据。 关联数据自动展开需显式声明
toArray()默认不递归展开关联对象。即使profile是一个ActiveRecord对象,不进extraFields()+ 显式请求,就不会转成数组。
若profile是hasOne()关系,且你在extraFields()中定义了它,toArray()会自动调用其toArray()—— 前提是该关联对象也支持Arrayable(它天然支持)。-
支持嵌套路径与回调处理
toArray()内部使用ArrayHelper::toArray()处理嵌套结构,因此支持点语法路径(如'profile.name')、闭包转换:public function fields() { return [ 'id', 'full_name' => function ($model) { return $model->firstName . ' ' . $model->lastName; }, ]; } 自动跳过敏感字段或未设置值
如果某个字段在fields()中声明,但模型属性为null且未设默认值,toArray()默认不会输出该键(除非你覆盖toArray()并传入$keepNulls = true)。
你也可以在fields()中用isset()或!empty()过滤动态字段。与
asArray()查询模式无关
注意:ActiveRecord::find()->asArray()->one()返回的是原生数组,绕过模型实例,完全不走toArray()。它只做数据库字段到数组的直映射,无字段过滤、无关联展开、无类型转换。这是两条不同路径。
本质上,toArray() 是面向资源表达层(如 REST API 响应) 的可控序列化入口;而 asArray() 是面向查询性能优化的底层数据获取方式。











