Laravel 8+ 模型工厂必须用 User::factory()->create() 静态调用,全局 factory() 函数已移除;工厂类须严格置于 database/factories/UserFactory.php,类名 UserFactory 且继承 Factory,$model = User::class 必须声明;字段定义须用 fake()->name() 而非 $this->faker->name;make() 不写库,create() 写库;count(5) 必须前置;关联需用 for()/has()/hasAttached(),且 for() 中的模型必须已 create() 入库。

Laravel 8+ 的模型工厂必须用 User::factory()->create() 这类静态调用,factory(User::class)->create() 全局函数已彻底移除,继续用会报 Call to undefined function factory() 或静默失败。
工厂类放哪儿、叫啥名、怎么写
三个硬性条件缺一不可,否则 User::factory() 会抛出 Unable to locate factory for [App\Models\User]:
- 文件路径必须是
database/factories/UserFactory.php——不能有子目录(比如database/factories/User/UserFactory.php就找不到) - 类名必须是
UserFactory,且继承Illuminate\Database\Eloquent\Factories\Factory -
protected $model = User::class;这行必须存在,Laravel 不靠文件名推断模型,只认这个属性
fake() vs $this->faker:别混用旧写法
新版定义字段时必须用 fake()->name(),不是 $this->faker->name。后者在 Laravel 8+ 会直接报错,因为 $this->faker 已被移除。
常见错误现象:Call to undefined property Database\Factories\UserFactory::$faker
正确写法示例:
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'password' => bcrypt('password'),
];
}
fake()->unique() 只对同一工厂实例内连续调用有效——User::factory()->count(10)->create() 安全,但循环里写 10 次 User::factory()->create() 可能撞邮箱。
make() 和 create() 行为差异直接影响测试速度和数据库状态
make() 只构造内存中的模型实例,不写入数据库,适合单元测试中避免 DB 依赖;create() 保存到数据库,返回已持久化的模型对象,适合功能测试或需要真实外键的场景。
-
withAttributes(['email' => 'test@example.com'])可覆盖默认字段,比在definition()里硬编码更灵活 -
count(5)必须放在create()前:User::factory()->count(5)->create()是批量插入,效率远高于循环调用 - Seeder 中执行大批量数据时,建议关闭模型事件:
User::withoutEvents(fn () => User::factory()->count(1000)->create())
关联模型怎么连:for()、has()、hasAttached()
关联不是靠手动设外键,而是用工厂方法自动维护关系链:
-
Post::factory()->for($user)->create():要求$user是已create()的模型实例,for()会自动填user_id -
User::factory()->has(Post::factory()->count(3))->create():一个用户带 3 篇文章,has()自动处理post.user_id -
User::factory()->hasAttached(Role::factory(), ['active' => true])->create():用于多对多中间表字段(如active),hasAttached()比手动attach()更可靠
注意:Post::factory()->for($user)->create() 中的 $user 不能是 make() 出来的临时对象,必须是已入库的实例——否则外键为空或触发约束异常。


















