If you run the command php artisan make:model
, here's a typical Model it would generate.
use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Database\Eloquent\Model; class Post extends Model{ use HasFactory;}
Let's look at it from the point of a totally new junior PHP developer.
Two questions they may ask:
extends Model
? What's inside of that Model
class?use HasFactory
? What's the difference between extends
and use
inside the class?The answers are below, one by one.
The keyword class ABC extends XYZ
means that ABC automatically has all the properties/methods from the XYZ class but may add more of its own properties/methods on top.
It's a typical parent-child relationship in OOP, also called "inheritance".
In human language, the explanation would be this: "Post is a Model, and inside of the Post class we will describe in more details WHAT KIND of model".
And the point is that many classes may extend the same class. So, Laravel has many Models that extend the same Model class. Same with Controllers and other typical classes.
If you look inside the Model class inside the vendor, you will see it's a huge file with 2,000+ lines of code. It contains a lot of well-known Eloquent features that you may override or enable/disable in your individual models:
Illuminate/Database/Eloquent/Model.php
abstract class Model ...{ // ... // You know this property, right? protected $table; // You can set the pagination default per Model protected $perPage = 15; // Yes, this method is executed when you call Post::all() public static function all($columns = ['*']) { return static::query()->get( is_array($columns) ? $columns : func_get_args() ); } // ...}
We cannot change any code in the /vendor
folder. That's why Laravel Models are created outside of it, extending the framework classes from the /vendor
. In other words, the framework defines the initial rules, but we may change them for our individual cases.
So, your individual Models "inherit" all the properties/methods of that Eloquent Model.
That also means that you can override their values:
app/Models/Post.php:
class Post extends Model{ protected $table = 'my_posts'; // The new default if you call Post::paginate() protected $perPage = 50;}
Ok, now let's get to that use HasFactory
thing.
Now, let's focus on these highlighted lines:
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Post extends Model{ use HasFactory; }
Is that HasFactory
a PHP class?
No, it's a Trait. Here's its source.
Illuminate/Database/Eloquent/Factories/HasFactory.php:
namespace Illuminate\Database\Eloquent\Factories; trait HasFactory{ public static function factory($count = null, $state = []) { $factory = static::newFactory() ?: Factory::factoryForModel(get_called_class()); return $factory ->count(is_numeric($count) ? $count : null) ->state(is_callable($count) || is_array($count) ? $count : $state); } protected static function newFactory() { // }}
As you can see, it's not a big piece of code. What it does is allowing you to create 10 "fake" posts in the Seeder:
Post::factory(10)->create();
Now, from the OOP point of view, HasFactory
is not a class, it's not "extended".
A trait is just a piece of functionality (methods/properties) that you can "glue into" any other PHP class.
In this case, many Eloquent models would benefit from this Model::factory()
behavior, so it is added automatically to any new Model you generate with php artisan make:model
command.
And that's the main point/benefit of traits: reusable code snippets in multiple PHP classes.
You can also add multiple traits into one PHP class, separating them by comma:
class User extends Model{ use HasFactory, SomeOtherTrait, AndAnotherTrait;}
This is exactly what is done in Laravel Model:
abstract class Model{ use Concerns\HasAttributes, Concerns\HasEvents, Concerns\HasGlobalScopes, Concerns\HasRelationships, Concerns\HasTimestamps, Concerns\HasUniqueIds, Concerns\HidesAttributes, Concerns\GuardsAttributes, ForwardsCalls;
If you prefer, you may also separate them, one per line:
class User extends Model{ use HasFactory; use SomeOtherTrait; use AndAnotherTrait;}