Lewati ke konten
Rama's logo Qisthi Ramadhani
Go back

PHP 8.4 Property Hooks Migration for Laravel: How to Fix

TL;DR

PHP 8.4 introduces property hooks (get/set) that allow defining accessor and mutator logic directly on class properties, replacing the need for magic __get/__set methods or Laravel’s attribute casting in many cases. Migrating to property hooks in a Laravel codebase requires understanding the interaction with Eloquent’s own accessor/mutator system (which uses PHP attributes since Laravel 9+), knowing where property hooks add value vs where they conflict, and handling edge cases with serialization, validation, and IDE support.. This guide walks you through identifying the symptoms, understanding the root cause, and implementing a production-tested fix with real code examples.


Symptoms

If you’re experiencing this issue, you’ll likely notice one or more of these signs in your application:

If any of these symptoms look familiar, you’re dealing with php 8.4 property hooks migration for laravel. Read on to understand why it happens and how to fix it properly.


Root Cause

PHP 8.4 introduces property hooks (get/set) that allow defining accessor and mutator logic directly on class properties, replacing the need for magic __get/__set methods or Laravel’s attribute casting in many cases. Migrating to property hooks in a Laravel codebase requires understanding the interaction with Eloquent’s own accessor/mutator system (which uses PHP attributes since Laravel 9+), knowing where property hooks add value vs where they conflict, and handling edge cases with serialization, validation, and IDE support.

Understanding the root cause is critical before applying a fix — treating only the symptoms often leads to the problem resurfacing in a different form, especially under production load.


How to Fix

Follow these steps in order. Each step builds on the previous one, and skipping steps may result in an incomplete fix.

Step 1: Understand the distinction: PHP 8.4 property hooks work on plain PHP classes (DTOs, Value Objects, Services). Eloquent model attributes should continue using Laravel’s Attribute casting system

Understand the distinction: PHP 8.4 property hooks work on plain PHP classes (DTOs, Value Objects, Services). Eloquent model attributes should continue using Laravel’s Attribute casting system

Step 2: Use property hooks for DTOs and Value Objects that don’t extend Eloquent Model

Use property hooks for DTOs and Value Objects that don’t extend Eloquent Model

Step 3: For service classes, replace getter/setter boilerplate with property hooks

For service classes, replace getter/setter boilerplate with property hooks

Step 4: Keep using Laravel’s Attribute::make(get: ..., set: ...) for Eloquent models

Keep using Laravel’s Attribute::make(get: ..., set: ...) for Eloquent models — property hooks don’t intercept Eloquent’s attribute access

Step 5: Update your PHPStan/Psalm config to support PHP 8.4 syntax

Update your PHPStan/Psalm config to support PHP 8.4 syntax

Step 6: Add property hooks to your team’s coding standards document

Add property hooks to your team’s coding standards document


Code Example

The following before/after comparison shows the core pattern you need to change. Pay attention to the comments explaining why each change matters.

Before (Broken)

// Old PHP: getter/setter boilerplate in a DTO
class MoneyDTO
{
    private int $cents;

    public function __construct(int $cents)
    {
        if ($cents < 0) {
            throw new InvalidArgumentException('Amount cannot be negative');
        }
        $this->cents = $cents;
    }

    public function getCents(): int
    {
        return $this->cents;
    }

    public function getDollars(): float
    {
        return $this->cents / 100;
    }
}

After (Fixed)

// PHP 8.4: property hooks eliminate boilerplate
class MoneyDTO
{
    public int $cents {
        set(int $value) {
            if ($value < 0) {
                throw new \InvalidArgumentException('Amount cannot be negative');
            }
            $this->cents = $value;
        }
    }

    public float $dollars {
        get => $this->cents / 100;
    }

    public function __construct(int $cents)
    {
        $this->cents = $cents; // triggers the set hook
    }
}

Key Takeaways


Difficulty Level

Intermediate

This guide assumes familiarity with the framework and its core tooling. You should understand basic database concepts, configuration patterns, and be comfortable reading framework source code when needed. Prior experience with similar issues will help but is not required.


Frequently Asked Questions

Do PHP 8.4 property hooks work with Eloquent models?

Not directly for database attributes. Eloquent uses its own attribute access system (__get/__set magic methods and the Attribute class) that bypasses native PHP property access. Use property hooks for non-Eloquent classes like DTOs, Services, and Value Objects. Continue using Laravel’s Attribute::make() for Eloquent model accessors and mutators.

Should I refactor all my Laravel getters/setters to property hooks?

No. Only refactor plain PHP classes (DTOs, Value Objects, Service classes) where getter/setter boilerplate adds no logic beyond simple validation or transformation. Leave Eloquent models using Laravel’s Attribute system, and don’t refactor working code just for syntax — do it when you’re already modifying the class.


Share this post on:
LLM-friendly version:
Open in ChatGPT Open in Claude

Related Posts


Previous Post
PestPHP Stress Testing for Health Endpoint Benchmarking: How to Fix
Next Post
PHPStan Level 9 Strict Typing Guide for Laravel: How to Fix