Software development for your future

Understanding Laravel’s Magic Methods

Do not try and bend the spoon. That’s impossible. Instead… only try to realize the truth. There is no function.

I was in a meeting with a client, and he wanted to understand more about how the workings of the program I created. That application was written using Laravel, a popular PHP framework. In the middle of the explanation I referred to Laravel’s magic methods and he started to chuckle. For a moment he thought I was pulling an explanation out of my coder’s hat, but once I continued on he realized I was not joking.

Magic methods are a set of pseudo-functions in php that allow the creation of dynamic properties and methods. Magic methods are marked by their double underscore preceding the function name. These pseudo functions define several, very common events in php objects including getters and setters.  Laravel makes great use of magic functions to allow for and enhance dynamic objects and methods. In fact, if you’ve done any object oriented programming then you’ve most likely already used a magic method, the constructor.

The Constructor, Getters and Setters

That’s correct. When a new class is created by `new ClassName()` php first looks for the function __construct(). The constructor following standard object oriented programming is used for initializing any set of properties. Similarly, when any property is read or modified, php has built in functions for those as well (__get(string $name), __set(string $name, $value)). So when you call `$object->property_name`, your object will first get a call to `__get(‘property_name’)`

Laravel Magic Methods

So how does Laravel take advantage of these methods? Let’s start with models because they will contain properties that match your database schema. If you notice when you create a model you don’t have to specify any properties like the example below:

class BadModel {
  public $id;
  public $user_name;
  public $password;
}

Instead, you create a blank model. You can stop here, but you’re probably going to dump data into the model so you can add a $fillable variable which defines properties that can be auto filled. Notice we didn’t add password, but that doesn’t mean the model doesn’t have access to the password.

class GoodModel extends Model {
  protected $fillable = ['user_name'];
}

The beauty of this lies in the extended Eloquent\Model class. This class stores properties in a protected array $attributes. When a property is read or changed, the respective magic method is called to pull that array key value. Instead of just returning the value, this allows other methods to be called which can perform actions on the value. For example, if we always wanted our user_name to only contain lower case letters we could add the following setter to our Good Model example.

class GoodModel extends Model {
  protected $fillable = ['user_name'];
  protected function setUserNameAttribute($value) {
    $this->attributes['user_name'] = strtolower($value);
  }
}

This even extends beyond simple properties. Let’s say that each user has many addresses, which we want to store in a different table. Now we add the following function to our GoodModel assuming the AddressModel exists.

class GoodModel extends Model {
  ...
  public function addresses()
  {
    return $this->hasMany('App\Address');
  }
}

This function returns a Relation object if called like a normal method `$object->addresses()` This is perfect if we want to chain other methods to the call such as where or  group_by. This is normal behavior, but the magic method also allows us to call the method as a property. In the getter, the Eloquent\Model checks if the property name is a method, and assumes the property is a relationship. With this assumption, you are now able to access the results as a Laravel collection by simply calling `$object->addresses` without the parenthesis. The model stores the results to prevent excessive calls to the database.

As you can see, in the model alone, Laravel makes extensive use of these magic methods. You can use these same methods on any object you create in php. The cons include no autofill for most IDEs and now to access the variable you have to perform a dictionary lookup. In my opinion, the flexibility of implementing properties with magic methods highly outweighs these small cons.