#[\Override] (PHP 8.3+) marks a method as overriding a parent or interface method. If that parent method is renamed or removed, PHP throws a fatal error when the class loads, instead of silently treating your method as a brand-new one. In Magento it's most useful on preferences and extended core classes, exactly where upgrades rename things.
Override a core method, upgrade Magento, and if that method got renamed, your override silently stops running. Nothing errors. Your code just isn't called anymore. #[\Override] turns that silent failure into a loud one.
Attributes you've already seen in Magento
You've probably run into PHP attributes already. They're the #[...] tags that sit above classes, methods or properties and add metadata without changing what the code does.
Magento core is full of them. Magento\Framework\App\RouterList uses #[\ReturnTypeWillChange] on its Iterator methods, and the integration and API-functional tests use #[DataFixture(...)] (from Magento\TestFramework\Fixture\DataFixture) to set up test data.
#[\Override] is a built-in one, like #[\ReturnTypeWillChange], and PHP itself enforces it.
A practical example of #[\Override] in Magento
Let's say we replace Magento's JSON serializer with our own via a preference, to add some stricter behavior:
<?php
declare(strict_types=1);
namespace Macademy\DebugBooster\Serialize\Serializer;
use Magento\Framework\Serialize\Serializer\Json as BaseJson;
class Json extends BaseJson
{
/**
* @inheritDoc
*/
#[\Override]
public function serialize($data): string
{
try {
return json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
} catch (\JsonException $e) {
throw new \InvalidArgumentException('Unable to serialize value. Error: ' . $e->getMessage());
}
}
/**
* @inheritDoc
*/
#[\Override]
public function unserialize($string): mixed
{
if ($string === null) {
throw new \InvalidArgumentException(
'Unable to unserialize value. Error: Parameter must be a string type, null given.'
);
}
try {
return json_decode($string, true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
throw new \InvalidArgumentException('Unable to unserialize value. Error: ' . $e->getMessage());
}
}
}The #[\Override] attribute explicitly says we intend to override serialize() and unserialize() from the parent class.
A few details matter here:
JSON_THROW_ON_ERRORmakesjson_encode()andjson_decode()throw a\JsonExceptioninstead of returningfalseornull. We catch it and rethrow\InvalidArgumentException, which is what callers ofSerializerInterfacealready expect.json_decode()getstrueas its second argument. Core'sunserialize()returns associative arrays, and everything that uses the serializer (the config cache, quote item options and more) depends on that. Passnullthere and you'd getstdClassobjects back, which breaks a lot of Magento at once.JSON_UNESCAPED_SLASHESmakes the output more readable, but a preference on the serializer changes serialization site-wide, including strings stored in config and cache.
That last point is the bigger lesson. Preferences on core classes are a last resort, after plugins and observers. But when you do need one, #[\Override] matters most, because you're now tied to a core class's method names.
What happens when #[\Override] fails
Let's pretend a future Magento release renames the parent method:
namespace Magento\Framework\Serialize\Serializer;
class Json implements SerializerInterface
{
public function encode($data)
{
$result = json_encode($data);
if (false === $result) {
throw new \InvalidArgumentException("Unable to encode value. Error: " . json_last_error_msg());
}
return $result;
}
}In this hypothetical update, serialize() became encode() to match json_encode().
FUN FACT: The default implementation of SerializerInterface once used PHP's built-in serialize() rather than json_encode(), which is why this method is named
serialize()to this day. Fun times! 😅
Without #[\Override], our serialize() would quietly become a new method that nothing calls, and our custom behavior would vanish. With it, PHP refuses to load the class:
PHP Fatal error: Macademy\DebugBooster\Serialize\Serializer\Json::serialize() has #[\Override] attribute, but no matching parent method exists in /var/www/html/app/code/Macademy/DebugBooster/Serialize/Serializer/Json.php on line 15It fails fast and it fails loudly. You catch it as soon as the class loads in dev or CI, long before a customer finds it on production.
What it doesn't catch: a parent method that keeps its name but changes its signature or behavior. #[\Override] only checks that a matching method exists. It's a guard against renames and removals, not a replacement for reading the release notes.
Which Magento versions support #[\Override]?
Any Magento install running on PHP 8.3 or newer. Going by Adobe's system requirements:
- 2.4.9 is supported on PHP 8.5.
- 2.4.8 (2.4.8-p5) is supported on PHP 8.4 and 8.3.
- 2.4.7 (2.4.7-p10) is supported on PHP 8.3 and 8.2.
So every supported release line has a PHP version that understands #[\Override]. The only setup that can't enforce it is 2.4.7 on PHP 8.2, and even there it's harmless: PHP 8.2 doesn't know the attribute, and attributes aren't validated unless something reflects on them, so it's simply ignored. That makes it safe to add today, and it starts working the moment you upgrade PHP.
Magento core itself doesn't use #[\Override] yet (there are no hits in vendor/magento on 2.4.9), so don't expect to find examples there. This one's on you to add in your own code.
Does #[\Override] work on properties?
Yes, as of PHP 8.5, which extends #[\Override] to properties. Since Magento 2.4.9 runs on PHP 8.5, you can use it there:
<?php
declare(strict_types=1);
namespace Macademy\DebugBooster\Block;
use Magento\Framework\View\Element\Template;
class Debug extends Template
{
#[\Override]
protected $_template = 'Macademy_DebugBooster::debug.phtml';
}Typo the property name, or have the parent drop it, and you get the same kind of error:
PHP Fatal error: Macademy\DebugBooster\Block\Debug::$_templat has #[\Override] attribute, but no matching parent property existsThis is handy on blocks and other classes where you customize behavior by redeclaring an inherited protected property. A misspelled $_template normally fails silently.
Does it cost anything?
No runtime cost worth measuring. PHP checks it when the class is linked to its parent, and OPcache caches that.
#[\Override] and static analysis
PHPStan can catch some of the same mistakes without the attribute, and you should run static analysis tools either way. I use both. Static analysis catches problems in CI, and #[\Override] catches them in any environment the code runs in, including the ones where nobody ran the analyzer.
Put #[\Override] on every method you override in a core class, a preference or a third-party module. It's one line, it costs nothing at runtime, and it turns your next upgrade's silent bug into an error with a file and line number.
If you're keeping an eye on newer PHP features, property hooks in PHP 8.4 are worth a look next.



