Well Laravel uses the magic __get method for this that is build into PHP. From there it tries to check if they property exists on the model. If it doesn't exists it keeps searching for other possibilities like relations and accessors.
But specifically for the accessor you can find the code here: https://github.com/laravel/framework/blob/5.8/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php#L302 If you look closely you see the following code:
// Model.php
public function __get($key)
{
return $this->getAttribute($key);
}
public function getAttribute($key)
{
// Check if the attribute exists or check if there is a method for the getter
// So for key "image" we basically check in the "hasGetMutator" method if
// the method "getImageAttribute" exists on the current class.
if (array_key_exists($key, $this->attributes) ||$this->hasGetMutator($key)) {
// Get the actual attribute
return $this->getAttributeValue($key);
}
}
public function getAttributeValue($key)
{
// Get the original value from the model based on the key
$value = $this->getAttributeFromArray($key);
// If the attribute has a get mutator, we will call that then return what
// it returns as the value, which is useful for transforming values on
// retrieval from the model to a form that is more useful for usage.
// "hasGetMutator" does the same check as before
if ($this->hasGetMutator($key)) {
// Get the actual mutated value, we also pass in the original value so we can mutate that
return $this->mutateAttribute($key, $value);
}
}
protected function mutateAttribute($key, $value)
{
// Basically call the method on the class
// In this case "getImageAttribute($value);
return $this->{'get'.Str::studly($key).'Attribute'}($value);
}
Note: I stripped some code to make it more clear!
For mutators it kinda works the same way! Instead of using the magic __get it uses the magic __set method from PHP. There is also a similair funtion for that
public function __set($key, $value)
{
$this->setAttribute($key, $value);
}
public function setAttribute($key, $value)
{
if ($this->hasSetMutator($key)) {
return $this->setMutatedAttributeValue($key, $value);
}
}
public function hasSetMutator($key)
{
return method_exists($this, 'set'.Str::studly($key).'Attribute');
}
protected function setMutatedAttributeValue($key, $value)
{
return $this->{'set'.Str::studly($key).'Attribute'}($value);
}
Let me know if this makes sense to you!