maxboychuk15 May 2026 14:10

We just upgraded one of our services from PHP 8.3 to 8.5 and hit a few issues with property hooks and Eloquent models. Sharing in case others run into the same.

The problem: We had models using the new property hook syntax to add custom logic to attribute access:

PHP
class Product extends Model
{
public string $price {
get => number_format($this->attributes['price'] / 100, 2);
set => $this->attributes['price'] = (int)($value * 100);
}
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

This worked fine until we called $product->toArray() — it threw a ReflectionException because Eloquent’s toArray() iterates over model attributes using reflection and doesn’t know what to do with hooked properties that aren’t in $attributes directly.

Also, $product->fill(['price' => 9.99]) bypassed the setter hook entirely — went straight to $this->attributes.

What we ended up doing: Reverting to Eloquent’s own $casts and accessor/mutator syntax (get / set attribute methods) for anything that needs to interact with ORM serialization. Property hooks are fine for non-model classes.

Anyone managed to make property hooks work correctly with Eloquent on 8.5? Or is this a known limitation until Laravel officially supports it?

Replies (2)
andriy_m15 May 2026 14:38

This is a known issue, there’s an open discussion on the Laravel internals repo. The core problem is that Eloquent’s magic attribute system (__get/__set) and PHP 8.5 property hooks operate at different levels — hooks are compile-time declarations, while Eloquent works with a dynamic $attributes array at runtime.

For now the official stance from the Laravel team is: use accessors/mutators (Attribute::make()) for Eloquent, and property hooks for everything else.

The fill() bypass issue you mentioned is actually by design — fill() calls setAttribute() which goes through the mutator pipeline, not through the PHP property hook. So those are two completely separate systems and they don’t compose cleanly.

0
simondev15 May 2026 16:30

Also worth noting: if you’re on Hyperf instead of Laravel, the situation is similar — Hyperf’s model layer inherits the same reflection-based serialization approach.

Practical advice: annotate hooked properties with @internal or keep them in separate value objects that aren’t ORM models. Mixing ORM magic with language-level property hooks before the frameworks catch up is asking for subtle bugs.

PHP 8.5 property hooks are excellent for domain objects and DTOs though. We’re using them heavily there with no issues.

0
Write a reply
Markdown. ```php blocks are runnable.