Accessors & Mutators
Modifying and accessing attributes with Accessors and Mutators
Accessors and Mutators allow you to transform model attributes before reading or writing. This feature allows you to keep data transformation logic in the model.
Accessors:
Accessors allow you to transform attributes before reading. Method name must be in format get{Attribute}Attribute and attribute name must be camelCase.
- Executed before reading attribute
- Method name: <code>get{Attribute}Attribute</code>
- Can use other attributes
- Can perform calculations
- Can format data
Mutators:
Mutators allow you to transform attributes before writing. Method name must be in format set{Attribute}Attribute.
- Executed before writing attribute
- Method name: <code>set{Attribute}Attribute</code>
- Can perform validation
- Can transform data
- Can perform encryption/hashing
Benefits:
- <strong>Data Transformation</strong>: Transform data in one place
- <strong>Consistency</strong>: Ensure consistency in data transformation
- <strong>Encapsulation</strong>: Keep transformation logic in model
- <strong>Reusability</strong>: Reuse transformation logic
- <strong>Type Safety</strong>: Automatic type conversion
Examples
Simple Accessor
<?php
class User extends Model
{
public function getFullNameAttribute()
{
return "{$this->first_name} {$this->last_name}";
}
public function getIsAdminAttribute()
{
return $this->role === 'admin';
}
}
// Usage
$user = User::find(1);
echo $user->full_name; // Accessor
echo $user->is_admin; // Accessor
Simple accessors for combining attributes and calculations.
Simple Mutator
<?php
class User extends Model
{
public function setPasswordAttribute($value)
{
$this->attributes['password'] = Hash::make($value);
}
public function setEmailAttribute($value)
{
$this->attributes['email'] = strtolower(trim($value));
}
}
// Usage
$user = new User();
$user->password = 'secret'; // Automatically hashed
$user->email = ' JOHN@EXAMPLE.COM '; // Automatically lowercased and trimmed
Simple mutators for hashing and normalizing data.
Accessor with Formatting
<?php
class Product extends Model
{
public function getFormattedPriceAttribute()
{
return '$' . number_format($this->price, 2);
}
public function getCreatedAtFormattedAttribute()
{
return $this->created_at->format('Y-m-d H:i:s');
}
public function getStatusBadgeAttribute()
{
return match($this->status) {
'active' => '<span class="badge badge-success">Active</span>',
'inactive' => '<span class="badge badge-danger">Inactive</span>',
default => '<span class="badge badge-secondary">Unknown</span>'
};
}
}
Accessors for formatting data for display.
Mutator with Validation
<?php
class User extends Model
{
public function setPhoneAttribute($value)
{
// Remove non-numeric characters
$cleaned = preg_replace('/[^0-9]/', '', $value);
// Validate phone number
if (strlen($cleaned) < 10) {
throw new \InvalidArgumentException('Invalid phone number');
}
$this->attributes['phone'] = $cleaned;
}
public function setCreditCardAttribute($value)
{
// Encrypt sensitive data
$this->attributes['credit_card'] = encrypt($value);
}
}
Mutators with validation and encryption for sensitive data.
Accessor with Relationships
<?php
class Order extends Model
{
public function getTotalItemsAttribute()
{
return $this->items()->sum('quantity');
}
public function getTotalAmountAttribute()
{
return $this->items()->sum(DB::raw('quantity * price'));
}
public function getIsCompleteAttribute()
{
return $this->status === 'completed' && $this->items()->count() > 0;
}
}
Accessors that use relationships.
Appending Accessors
<?php
class User extends Model
{
protected $appends = ['full_name', 'is_admin'];
public function getFullNameAttribute()
{
return "{$this->first_name} {$this->last_name}";
}
public function getIsAdminAttribute()
{
return $this->role === 'admin';
}
}
// Accessors are automatically included in JSON/Array
$user = User::find(1);
$user->toArray(); // Includes full_name and is_admin
$user->toJson(); // Includes full_name and is_admin
Using $appends to automatically include accessors in JSON/Array.
Conditional Mutators
<?php
class User extends Model
{
public function setPasswordAttribute($value)
{
// Only hash if value is not already hashed
if (!empty($value) && !Hash::needsRehash($value)) {
$this->attributes['password'] = $value;
} else {
$this->attributes['password'] = Hash::make($value);
}
}
public function setSlugAttribute($value)
{
// Generate slug if not provided
if (empty($value) && !empty($this->attributes['title'])) {
$this->attributes['slug'] = Str::slug($this->attributes['title']);
} else {
$this->attributes['slug'] = Str::slug($value);
}
}
}
Mutators with conditional logic for smart transformations.
Use Cases
- Combining multiple attributes into one attribute
- Formatting data for display
- Hashing and encrypting sensitive data
- Normalizing and cleaning user input
- Calculations based on attributes
- Type conversion and casting
Common Mistakes
- Forgetting camelCase in accessor/mutator names
- Using accessor for complex business logic
- Mutator with side effects causing issues
- Forgetting return statement in accessor
- Using accessor for data that should be stored in database
- Accessor with expensive operations affecting performance
Best Practices
- Use accessors for simple transformations
- Use mutators for data normalization
- Use $appends to automatically include accessors
- Keep accessor logic simple
- Use mutators for security-sensitive operations
- Keep accessor names descriptive
- Use caching for expensive accessors
Edge Cases
- Accessors with circular dependencies
- Mutators with validation errors
- Accessors in JSON serialization
- Mutators with mass assignment
- Accessors with relationships that may cause N+1
- Mutators with complex conditional logic
Performance Notes
- Accessors overhead is very low
- Avoid expensive operations in accessors
- Use caching for expensive accessors
- Mutators only execute on write
- Use $appends with caution as they execute on every serialization
Security Notes
- Use mutators for hashing passwords
- Use mutators for encrypting sensitive data
- Ensure accessors don't expose sensitive data
- Use validation in mutators
- Ensure accessors don't have SQL injection
Interview Points
- What are Accessor and Mutator and what is the difference?
- How can you include accessor in JSON?
- When should you use accessor and when mutator?
- How can you use accessor with relationships?
- What is the difference between accessor and attribute casting?
- How can you define conditional mutator?
Version Notes
- Laravel 11.x: Improved performance in accessor/mutator execution
- Laravel 11.x: Better support for attribute casting
- Laravel 10.x: Improved $appends functionality
- Laravel 9.x: Improved accessor caching