
Schema::getColumnListing() 默认返回按字母排序的列名,若需保持建表时的物理顺序,应改用模型实例的属性键顺序或直接查询系统表。
laravel 获取数据库表字段的原始定义顺序(非字母序)
在 Laravel 开发中,Schema::getColumnListing($table) 是获取指定数据表所有列名的常用方法。但需注意:该方法返回的列名顺序并非数据库中字段的创建顺序,而是由底层数据库驱动(如 MySQL 的 SHOW COLUMNS 或 PostgreSQL 的 information_schema 查询)决定的默认排序方式——通常为字母升序。这与开发者期望的“建表迁移中定义的物理顺序”不一致,尤其在生成动态表单、导出结构或调试字段映射时易引发混淆。
要准确获取字段在表结构中的原始定义顺序(即 CREATE TABLE 语句中声明的顺序),推荐以下两种可靠方案:
✅ 方案一:通过模型实例的原始属性键(推荐,轻量且兼容性好)
利用 Eloquent 模型从数据库读取一条记录后,其 getOriginal() 方法返回的是按数据库实际返回顺序组织的属性数组(MySQL 驱动下严格遵循 SELECT * 的字段顺序,而该顺序即为建表顺序)。因此可安全提取键名:
use Illuminate\Support\Facades\Schema;
// 假设 User 模型已存在且对应 users 表
$user = \App\Models\User::query()->select('*')->first();
if ($user) {
$columnOrder = array_keys($user->getOriginal());
// 输出: ["id", "name", "email", "email_verified_at", "password", "remember_token", "created_at", "updated_at"]
dd($columnOrder);
} else {
// 若表为空,可插入一条测试记录再查询,或改用方案二
}⚠️ 注意事项:
- 此方法依赖数据库驱动对 SELECT * 字段顺序的保证(主流驱动如 MySQL、PostgreSQL、SQLite 均满足);
- 若表无数据,first() 返回 null,需提前处理空值(例如用 take(1)->get()->first() 或结合 DB::select() 手动执行 DESCRIBE);
- 不适用于只读连接或禁止 SELECT 的受限环境。
✅ 方案二:直接查询数据库系统表(精确、无需数据)
绕过 Eloquent,使用原生 SQL 查询 information_schema.COLUMNS(MySQL/PostgreSQL)或 sqlite_master(SQLite),按 ORDINAL_POSITION 排序确保物理顺序:
use Illuminate\Support\Facades\DB;
$tableName = (new \App\Models\User)->getTable();
$columns = DB::select("
SELECT COLUMN_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = ?
AND TABLE_NAME = ?
ORDER BY ORDINAL_POSITION
", [DB::getDatabaseName(), $tableName]);
$columnOrder = array_column($columns, 'COLUMN_NAME');
dd($columnOrder);✅ 优势:不依赖表中是否存在数据,结果 100% 反映建表顺序;
❗ 注意:需确保应用有权限访问 information_schema,部分云数据库(如 AWS RDS 的某些配置)可能限制此权限。
? 总结
- Schema::getColumnListing() 不保证物理顺序,仅作快速枚举用途;
- 生产环境中优先采用 方案一(模型 getOriginal() 键名),简洁高效;
- 对空表或高精度要求场景,选用 方案二(ORDINAL_POSITION 查询);
- 切勿依赖字段名排序逻辑实现业务关键流程——始终以数据库元数据或模型契约为准。


















