Explicitly marking subclass methods as "overrides" in PHP 8.3
The #[\Override]
attribute is a new attribute that will be introduced in PHP 8.3. It will be used to mark a method as overriding a parent method.
Before we get into the details of the #[\Override]
attribute, let’s first understand the problem it’s trying to solve.
The problem
Essentially, when a class extends another class, it can override the methods of the parent class.
Check this simple example.
class ParentClass
{
public function foo(int $a, string $b)
{
return "Parent";
}
}
class ChildClass extends ParentClass
{
public function foo(int $a, string $b)
{
return "Child";
}
}
$child = new ChildClass();
$child->foo(1, "2");
// Child
As you can tell, here, the foo()
method of the ChildClass
is overriding the foo()
method of the ParentClass
. And when a child class is overriding a method of the parent class, it is important to make sure that the child class method has the same signature as the parent class method.
So, if we change the signature of the foo()
method of the ChildClass
to something like this,
class ChildClass extends ParentClass
{
public function foo(int $a)
{
return "Child";
}
}
Then, it will result in a fatal error that says the declaration of the child class method is not compatible with the parent class method.
PHP Fatal error: Declaration of ChildClass::foo(int $a)
must be compatible with ParentClass::foo(int $a, string $b)
in /workspace/index.php on line 13
This is how PHP makes sure that the child class method is overriding the parent class method. That’s fair enough.
But there isn’t a way to check this in reverse.
Meaning, if the child class is overriding the parent class method and the signature of the method in the parent class changes, then there is no way to verify if the child class method is overriding any method of the parent class or not.
This is where the #[\Override]
attribute comes into the picture.
The #[\Override]
attribute
The
#[\Override]
attribute can be used to mark a method as overriding a parent method. And if the method is not overriding the method of the same name or signature of the parent class, then it will result in a compile-time error.
💡 Fun fact: Java has a similar
@Override
annotation which is used to mark a method as overriding a parent method. And it works in the same way as the#[\Override]
attribute.
So, we can add the #[\Override]
attribute to the foo()
method of the ChildClass
like this in our previous example.
class ChildClass extends ParentClass
{
#[\Override]
public function foo(int $a, string $b)
{
return "Child";
}
}
Now, if the signature of the foo()
method of the ParentClass
changes, then it will result in a compile-time error.
class ParentClass
{
public function foo(int $a)
{
return "Parent";
}
}
The error would look something like this.
Fatal error: ChildClass::foo() has #[\Override] attribute,
but no matching parent method exists
The same goes when a class is implementing an interface and marking a method as overriding a method of the interface.
interface Foo
{
public function foo(int $a, string $b);
}
class Bar implements Foo
{
#[\Override]
public function foo(int $a, string $b)
{
return "Bar";
}
}
Here are all the rules for using the #[\Override]
attribute.
- Public and protected methods of a parent class or implemented interface satisfy
#[\Override]
.- Abstract methods satisfy
#[\Override]
. - Static methods behave as instance methods.
- Abstract methods satisfy
- Private methods of a parent class do not satisfy
#[\Override]
, because they are not part of the externally visible API. __construct()
of a parent class does not satisfy#[\Override]
, because it’s not part of the API of an already-constructed object.- The attribute is ignored on traits, but:
- Abstract methods in a used trait satisfy
#[\Override]
. - Regular methods in a used trait that are “shadowed” by a method in the class using the trait do not satisfy
#[\Override]
. - Methods from a used trait behave as if the method definition was copied and pasted into the target class. Specifically the
#[\Override]
attribute on a trait method requires the existence of a matching method in a parent class or implemented interface.
- Abstract methods in a used trait satisfy
#[\Override]
works as expected on enums and anonymous classes.#[\Override]
works as expected on an interface. A matching method needs to exist in a parent interface.
Like this article?
Buy me a coffee👋 Hi there! I'm Amit. I write articles about all things web development. You can become a sponsor on my blog to help me continue my writing journey and get your brand in front of thousands of eyes.