Eloquent performance quick tip
Improve Laravel performance with this simple trick!
If you use Eloquent relationships, even if you have followed Laravel's naming convention, always provide the $name/$relation parameter for the relationship methods like belongsTo(), morphTo(), belongsToMany() or morphToMany(), regardless.
Example from my codebase:
public function recordable()
{
return $this->morphTo(__FUNCTION__);
}
public function city()
{
return $this->belongsTo(Country::class, 'country_id', 'id', __FUNCTION__)
}
If you don't provide that argument, Laravel will use the debug_backtrace() to get the relation name, which is resource intensive, and those Eloquent relationship calls can quickly add up.
Take a look at Laravel's internals:
// MorphTo Example
public function morphTo($name = null, $type = null, $id = null)
{
$name = $name ?: $this->guessBelongsToRelation();
list($type, $id) = $this->getMorphs(
Str::snake($name), $type, $id
);
return empty($class = $this->{$type})
? $this->morphEagerTo($name, $type, $id)
: $this->morphInstanceTo($class, $name, $type, $id);
}
protected function guessBelongsToRelation()
{
list($one, $two, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
return $caller['function'];
}
// BelongsToMany Example
public function belongsToMany($related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, $parentKey = null, $relatedKey = null, $relation = null)
{
if (is_null($relation)) {
$relation = $this->guessBelongsToManyRelation();
}
$instance = $this->newRelatedInstance($related);
$foreignPivotKey = $foreignPivotKey ?: $this->getForeignKey();
$relatedPivotKey = $relatedPivotKey ?: $instance->getForeignKey();
if (is_null($table)) {
$table = $this->joiningTable($related);
}
return $this->newBelongsToMany(
$instance->newQuery(), $this, $table, $foreignPivotKey,
$relatedPivotKey, $parentKey ?: $this->getKeyName(),
$relatedKey ?: $instance->getKeyName(), $relation
);
}
protected function guessBelongsToManyRelation()
{
$caller = Arr::first(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), function ($trace) {
return ! in_array($trace['function'], Model::$manyMethods);
});
return ! is_null($caller) ? $caller['function'] : null;
}
That's it, folks, I said it was a quick tip! ;)
P.S. Many micros make a macro, so don't come at me with the "That's a micro-optimization argument", that's not an excuse for being lazy :)
Last updated: 1 year ago
2636