Laravel Eloquent子类调用父类方法返回子类实例问题求助
这其实是Laravel Eloquent ORM的预期行为,核心和它的查询构建器上下文绑定机制有关,我来帮你拆解明白:
1. 非静态方法的上下文陷阱
当你在EmployeeFormSubmission子类的实例上调用父类的getFormSubmissions方法时,哪怕方法里写了FormSubmission::whereIn,Eloquent的查询构建器也会跟着当前执行代码的模型上下文走——因为你是从子类实例触发的调用,底层会默认把查询结果实例化为当前模型(也就是EmployeeFormSubmission),这是Eloquent为了支持模型继承特意设计的特性。
2. 为什么parent::whereIn也没用?
parent::whereIn只是调用了父类的whereIn方法,但查询构建器的上下文早就绑定到当前子类上了。whereIn这类查询方法最终返回的查询构建器实例,它的model属性已经被设置成了EmployeeFormSubmission,所以结果自然还是子类实例。
3. 静态方法正常的原因
当你把getFormSubmissions改成静态方法并通过FormSubmission::getFormSubmissions调用时,静态方法的上下文是FormSubmission类本身,查询构建器会直接绑定到父类,返回的实例自然就是FormSubmission了。
解决方案:强制指定查询上下文
如果需要在子类调用父类方法时返回父类实例,有两种简单的实现方式:
方式一:使用newQuery()明确指定模型
在父类的getFormSubmissions方法里,手动创建父类的查询构建器:
public function getFormSubmissions() { // 明确基于FormSubmission创建查询构建器 return (new FormSubmission)->newQuery() ->whereIn('your_column', $your_values) ->get(); }
方式二:使用query()方法替代直接调用
query()方法会返回绑定到当前类的查询构建器,这里直接用FormSubmission::query()就能确保上下文是父类:
public function getFormSubmissions() { return FormSubmission::query() ->whereIn('your_column', $your_values) ->get(); }
内容的提问来源于stack exchange,提问作者Martin Joiner

