PHP interfaces, traits, and abstract classes
Share a contract with an interface, share code with a trait, and share both with an abstract base.
On this page
PHP classes and inheritance.
- Share a contract with an interface, share code with a trait, and share both with an abstract base.
- Predict the sample output and explain the state changes.
- Complete the practice task and check the boundary cases.
The concept
PHP supports single inheritance, so a class has only one parent. An interface lists method signatures that implementing classes must provide, and a class can implement many interfaces. A trait is a reusable set of methods that is copied into a class with use. It is the way to share code between classes that are not related by inheritance.
An abstract class can combine both: it implements an interface, uses a trait, and leaves the remaining methods abstract. static::class refers to the actual class of the object, so one trait method can describe any subclass. final prevents further extension. Code that is typed against the interface works with every implementation.
Code example
<?php
interface Shape
{
public function area(): float;
}
trait Describes
{
public function describe(): string
{
return static::class . " with area " . number_format($this->area(), 2);
}
}
abstract class Base implements Shape
{
use Describes;
}
final class Circle extends Base
{
public function __construct(private float $radius) {}
public function area(): float
{
return M_PI * $this->radius ** 2;
}
}
final class Rect extends Base
{
public function __construct(private float $width, private float $height) {}
public function area(): float
{
return $this->width * $this->height;
}
}
foreach ([new Circle(1.5), new Rect(2, 3.5)] as $shape) {
echo $shape->describe(), "\n";
}
echo (new Circle(1)) instanceof Shape ? "a Circle is a Shape" : "not a Shape", "\n";Circle with area 7.07 Rect with area 7.00 a Circle is a Shape
Follow the code
Open the walkthrough to inspect the example one step at a time.
Show guided walkthrough
<?phpinterface Shape{ public function area(): float;} trait Describes{ public function describe(): string { return static::class . " with area " . number_format($this->area(), 2); }} abstract class Base implements Shape{ use Describes;} final class Circle extends Base{ public function __construct(private float $radius) {} public function area(): float { return M_PI * $this->radius ** 2; }} final class Rect extends Base{ public function __construct(private float $width, private float $height) {} public function area(): float { return $this->width * $this->height; }} foreach ([new Circle(1.5), new Rect(2, 3.5)] as $shape) { echo $shape->describe(), "\n";}echo (new Circle(1)) instanceof Shape ? "a Circle is a Shape" : "not a Shape", "\n";Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| A contract: every shape has an area. | — | — | |
| Reusable code. It can call area() because the classes that use it provide one. | — | — | |
| Base promises the interface but leaves area() to the subclasses. | — | — | |
| Constructor promotion creates the private property. | — | — | |
| static::class gives the real class name, and area() is the subclass's version. | — | Circle with area 7.07 Rect with area 7.00 | |
| instanceof also accepts interfaces. | — | Circle with area 7.07 Rect with area 7.00 a Circle is a Shape |
Behind the scenes
How PHP processes this code
The PHP runtime executes the script. echo writes to the response or terminal output.
Cost and common mistakes
Each call is O(1).
- Two traits with a method of the same name conflict. Resolve it with insteadof or as in the use block.
- Traits are not types. You cannot write a parameter type of Describes.
- number_format rounds for display only; keep the full float for calculations.
Try it yourself
Where would you declare a method that all shapes must implement?
Reveal answer and reasoning
In the Shape interface. Every class that implements it must then provide the method.