PHP has single inheritance for classes. Interfaces say what a class must provide, abstract classes share partial implementations, and traits copy members into a class. Class basics are on the Classes page.
Interfaces
interface Name [extends Interface {, Interface}]
{
{constant | method signature | property with hooks}
}
interface Shape
{
const SIDES = 0;
public function area(): float;
}
final class Circle implements Shape, Countable
{
public function __construct(private float $r) {}
public function area(): float { return M_PI * $this->r ** 2; }
public function count(): int { return 1; }
}
- Interface names share a namespace with classes, traits and enums.
- A class implements any number of interfaces, and must provide each method with a
compatible signature, or a fatal
error occurs.
extendscomes beforeimplements. - Interface methods must be
public. Static methods and magic methods are allowed. A constructor is allowed, but strongly discouraged. - An interface can extend several interfaces at once.
- An abstract class may leave part of an interface unimplemented, for its concrete children.
- Two interfaces with the same constant name cannot both be implemented by a class, unless it overrides it. Since PHP 8.1 an implementing class may override an interface constant; before that it could not.
Interface properties
Since PHP 8.4 an interface may require properties, stating whether a value can be read, written or both. Such a declaration is public.
interface Named
{
public string $label { get; }
public string $slug { get; set; }
}
A class satisfies it with a public property, or a virtual property with the required
hooks. A readonly property satisfies a get requirement. A
requirement that includes set cannot be met by a
readonly property.
Abstract classes
abstract class Report
{
abstract protected function rows(): array;
public function count(): int { return count($this->rows()); }
}
abstract classcannot be instantiated, and a class with any abstract member must be declared abstract.- An abstract method has a signature and no body. It is
publicorprotected, notprivate. A child must define every abstract method it inherits, or be abstract itself, with a compatible signature. - The child may add optional parameters that the parent did not declare.
Abstract properties
Since PHP 8.4, an abstract property declares what a child must provide, and may already implement the other half. Visibility may be widened when implementing.
abstract class Base
{
abstract public string $id { get; }
}
class Row extends Base
{
public string $id = 'x';
}
Traits
A trait is a group of methods and properties that the compiler copies into every class that uses it (PHP 5.4). It cannot be instantiated, and a class that uses it does not become an instance of it.
trait Logs
{
protected array $log = [];
public function log(string $line): void
{
$this->log[] = static::class . ': ' . $line;
}
}
class Mailer
{
use Logs;
}
(new Mailer)->log('sent');
- Within a class body,
useinserts traits. Several traits can be listed, separated by commas. - Members declared in the class override trait members, and trait members override
inherited ones. A trait method may call
parent::. - A trait may declare abstract methods, of any visibility, to require them from the class. Since PHP 8.0 their signatures are checked.
- A trait can have
staticmethods and properties. Each class using the trait has its own copy of a trait’s static property; since PHP 8.3 a child class’s use gets a distinct one too. Calling a static member directly on the trait is deprecated since PHP 8.1. - A trait can use other traits, and can define constants since PHP 8.2.
- A class cannot declare a property or constant with the same name as a trait’s unless it is compatible: the same visibility, type, modifier and initial value.
- In a trait,
__CLASS__andstatic::classgive the using class, and__TRAIT__gives the trait.
Conflict resolution
If two traits used by a class define a method of the same name, compilation fails
unless the class says which to use. Inside braces after the use list,
insteadof selects a method, and as adds an alias or changes
visibility.
trait A { public function hello() { return 'A'; } public function bye() { return 'A'; } }
trait B { public function hello() { return 'B'; } public function bye() { return 'B'; } }
class Talker
{
use A, B {
A::hello insteadof B; // use A's hello
B::bye insteadof A; // use B's bye
B::hello as protected helloB; // keep B's hello under another name
A::bye as byeA;
}
}
as adds a name; it does not rename the original| Form | Effect |
|---|---|
A::m insteadof B; | Use A’s m, excluding B’s |
m as alias; | Adds another name |
m as protected; | Changes the visibility of m in this class |
m as private alias; | Adds a name with that visibility |
m as final; | Prevents child classes overriding the method (PHP 8.3) |
Since PHP 8.5 traits are bound to a class before its parent class. A trait’s property or constant now takes precedence over a same-named inherited one instead of raising a fatal error. Method resolution is unchanged.