yii2 restful接口应优先使用asarray()提升性能,因其跳过对象实例化、getter调用和关联加载,实测提速4–10倍;需配合fields()精简字段、with()预加载关联,并在必要时改用普通controller以彻底绕过activerecord开销。

Yii2 RESTful 接口默认返回完整 ActiveRecord 对象,确实会明显拖慢响应速度。这不是“快一点”或“慢一点”的问题,而是对象实例化 + getter 触发 + 关联加载 + toArray 深度遍历这一整套流程带来的可测量开销。
关键差距在于:是否创建 PHP 对象实例。
对象实例化是最大瓶颈
ActiveRecord 默认返回 ActiveRecord[] 数组,每个元素都是一个完整对象:
- 构造函数执行(含事件触发)
- 属性赋值(含类型转换、默认值填充)
- 所有定义的 getter 方法可能被
toArray()自动调用(比如$model->full_name、$model->is_active) - 若未显式控制,
toArray()还会递归加载关联模型(如profile、orders),引发 N+1 查询或额外 SQL
而 asArray() 跳过全部对象层,直接返回二维原生数组:
// 慢:500 条记录 → 创建 500 个 User 对象 + 各种开销 User::find()->all(); // 快:500 条记录 → 仅一次 PDO fetchAll,零对象构造 User::find()->asArray()->all();
实测中,在中等复杂度模型(含 3–5 个字段、1–2 个简单 getter、无关联)下:
-
->all():平均耗时 8–15ms / 100 行 -
->asArray()->all():平均耗时 1.2–2.5ms / 100 行
提速约 4–6 倍;若模型含 virtual attributes 或 relation 加载,差距可达 10 倍以上。
但 asArray() 不能直接用于 ActiveController
yii\rest\ActiveController 的默认行为基于对象语义:它依赖 findModel() 返回模型实例,再调用 toArray() 序列化。你不能在控制器里简单写 User::find()->asArray()->all() 然后 return $data —— 这会绕过 Serializer,丢失分页、状态码、HATEOAS 链接、expand 支持等 REST 特性。
正确提速路径是在不破坏 REST 流程的前提下,让序列化过程尽可能轻量:
- 在模型中重写
fields(),只保留必要字段 - 显式禁用不需要的 getter(避免
toArray()自动调用) - 关联数据改用
asArray()->with('relation')预加载,而非对象级->getRelation()->one() - 若接口纯数据导出、无业务逻辑,考虑不用
ActiveController,改用普通yii\web\Controller+ 手动asArray()+JsonResponseFormatter
真实场景建议组合
-
单列表接口(如
/users):// 在 User 模型中 public function fields() { return ['id', 'name', 'email', 'created_at']; }✅ 避免 password_hash、token、settings 等敏感/冗余字段参与序列化
✅ 不触发getProfile()、getAvatarUrl()等 getter -
带关联的列表(如
/users?expand=profile):// 在控制器 index() 中临时调整查询(不推荐长期用,应封装进 find()) $query = User::find()->asArray()->with('profile'); return $query->all(); // ⚠️注意:这仍需配合自定义 Serializer 或降级为普通 Controller -
高频只读接口(如用户简档、配置项):
- 直接使用
Query或Command原生 SQL +asArray() - 绕过 ActiveRecord,响应时间可压到 0.3–0.8ms / 100 行(见 TechEmpower raw benchmark)
- 直接使用
不复杂但容易忽略:性能提升不靠黑科技,而在于切断不必要的对象生命周期和自动行为。











