yii2中toarray()比asarray()慢10–15倍,因前者触发getter、关联遍历、事件等对象开销,后者跳过实例化直接返回原生数组;读取场景应优先用asarray()。

性能差得非常明显,但不是“几个数量级”,而是几倍到十几倍的差距,具体取决于数据量、模型复杂度和关联关系深度。
核心原因:对象实例化开销巨大
Yii2 中 toArray() 不是简单序列化,它会:
- 触发所有 getter 方法(含自定义逻辑、关联计算)
- 递归处理关联模型(
with()加载后仍要逐个调用toArray()) - 执行属性过滤、类型转换、事件(如
beforeSerialize) - 每次调用都新建数组、复制属性、检查可见性
而 asArray() 是查询层直接返回原生数组,跳过整个 ActiveRecord 实例化流程——不创建对象、不调用构造函数、不加载行为(Behaviors)、不触发事件。
典型场景对比(1000 条记录)
假设有一张 user 表,带一个简单 profile 关联:
-
逐条
toArray():约 800–1200ms(含 1000 次对象构建 + 1000 次关联遍历 + 1000 次数组转换) -
一次性
asArray():约 40–70ms(纯 PDO 数据映射,无 PHP 对象开销)
实测差距通常在 10 倍到 15 倍之间,极端情况(深关联、重逻辑 getter)可能接近 20 倍,但达不到百倍(数量级跃迁)。
怎么选?看用途,不是看习惯
不需要 ActiveRecord 功能时,必须用 asArray():
- 只做数据导出、API 返回、前端渲染(无服务端业务逻辑)
- 批量写入/同步、报表统计、后台任务
- 与缓存(Redis/JSON)交互,避免序列化 ActiveRecords
只有需要以下能力时,才保留对象形态:
- 调用模型方法(
$user->getFullName()) - 使用验证(
$model->validate()) - 依赖事件或行为(日志、审计、自动填充)
- 后续要保存或更新(
$model->save())
小技巧:混合使用更高效
不必非此即彼。常见优化模式:
- 查列表用
asArray(),关键操作再按需实例化单条:User::findOne($id) - 用
select()明确字段,配合asArray()进一步减少数据传输 - 关联数据也走
asArray():User::find()->with('profile')->asArray()->all(),比逐条快得多
本质上,这是数据读取层和领域模型层的职责分离——读快,写稳,别让读操作背负写逻辑的包袱。











