如何在不实例化模型的情况下通过代码获取关联数据?
不实例化模型获取关联数据
我有一段可正常运行的代码,能够获取具有指定关联值(比如ID为1、2或3的标签)的某类模型集合:
<?php public function getEntitiesWithRelationValues($entityType, $relations = []) { $related = new EloquentCollection(); $locale = App::getLocale(); $entityType = new $entityType(); // 这里是否不合理? // $entityType = new ReflectionClass($entityType); // 这么写会报错:"ReflectionClass undefined method {$relation}" foreach ($relations as $relation => $modelKeys) { if ($entityType->{$relation}()->exists()) { $relatedClass = get_class($entityType->{$relation}()->getRelated()); $relationPrimaryKeyName = ($instance = new $relatedClass)->getQualifiedKeyName(); $relationEntities = $entityType::where('published->' . $locale, true) ->whereHas($relation, function (Builder $query) use($modelKeys, $relationPrimaryKeyName) { $query->whereIn($relationPrimaryKeyName, $modelKeys); }) ->get() ->sortKeysDesc() ->take(10); $related = $related->concat($relationEntities->except($related->modelKeys())); } } return $related; }
我认为$entityType = new $entityType();这段代码不够合理,因为我不想创建新模型实例。尝试用ReflectionClass时会抛出“ReflectionClass undefined method {$relation}”错误。请问如何在不加载/实例化模型的情况下获取某类模型的关联数据?
解决方案
首先明确:Laravel的关联方法是实例方法,必须依赖模型实例才能调用(关联方法需要$this上下文获取模型表名、主键等信息),完全不实例化模型获取关联信息并不现实,但可以优化实现逻辑:
1. 保留实例化但优化写法
实例化空模型的开销极低(仅创建内存对象,无数据库查询),你当前代码仅实例化一次(循环外),完全可以接受。若想让代码更贴合Laravel风格,可用容器解析:
// 替换原 $entityType = new $entityType(); $modelInstance = app($entityType);
2. 用反射预先校验关联合法性
若想避免调用不存在的关联方法,可通过反射先校验模型是否有合法的关联方法,但最终仍需实例化模型调用关联:
$reflection = new ReflectionClass($entityType); foreach ($relations as $relation => $modelKeys) { if (!$reflection->hasMethod($relation)) { continue; } $method = $reflection->getMethod($relation); $returnType = $method->getReturnType(); if (!$returnType || !is_subclass_of($returnType->getName(), \Illuminate\Database\Eloquent\Relations\Relation::class)) { continue; } $modelInstance = $reflection->newInstance(); // 后续关联逻辑和原代码一致 }
3. 简化静态查询逻辑
若能保证传入的$relations均为模型合法关联,可直接用静态whereHas查询,但获取关联模型主键仍需实例化关联模型:
public function getEntitiesWithRelationValues($entityType, $relations = []) { $related = new EloquentCollection(); $locale = App::getLocale(); foreach ($relations as $relation => $modelKeys) { $modelInstance = new $entityType(); $relatedClass = get_class($modelInstance->{$relation}()->getRelated()); $relationEntities = $entityType::where('published->' . $locale, true) ->whereHas($relation, function (Builder $query) use($modelKeys, $relatedClass) { $query->whereIn($relatedClass::getQualifiedKeyName(), $modelKeys); }) ->get() ->sortKeysDesc() ->take(10); $related = $related->concat($relationEntities->except($related->modelKeys())); } return $related; }
总结
完全不实例化模型获取关联元信息(关联模型类、主键等)无法实现,因为这些信息绑定在模型实例的关联方法中。但空模型实例的开销可忽略,无需过度担忧。若追求代码风格统一,用app($entityType)替代直接new即可。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

