Skip to content
Theory · Inheritance and interfaces · lesson 3 of 8

Abstract classes and interfaces

In the previous lesson, a child class received ready methods from its parent. Sometimes, though, the parent itself does not know how to do part of the work. Take shapes: a square and a circle both have an area, but they compute it differently, and you cannot build a "shape in general".

In the family of blueprints, this is a template blueprint: the walls and the roof are drawn, and where the kitchen should be it says "draw it yourself". Nobody builds a house from a template; it gets completed first.

There is another document too, a job description. It lists what a worker must be able to do, but not how exactly to do it.

In PHP, the template is an abstract class, and the job description is an interface.

Abstract class

An abstract class is a class marked abstract that you cannot create an object of: it exists only as a parent for other classes.

PHP
<?php

abstract class Shape
{
    public function __construct(protected float $size) {}

    abstract public function area(): float;

    public function describe(): string
    {
        return $this::class . ' ' . $this->area();
    }
}

Let's walk through it step by step:

  1. abstract class Shape declares a template: you cannot build a Shape object.
  2. The constructor and the property $size are the same as in an ordinary class: an abstract class can hold data.
  3. abstract public function area(): float; is an abstract method. It has only a signature, that is, the name, the parameters and the return type, and a semicolon instead of a body. Every child class must write it.
  4. describe() is a ready method. It calls $this->area() even though area() has no body in Shape: as you already know, $this finds the version from the object's class. And $this::class gives the name of that class as a string.

Here the template picture falls short: in PHP you never fill in the template itself; you write a child class with the missing methods.

Interface

An interface is a list of methods a class promises to have, without their code. You declare it with the word interface, and a class signs up for it with the word implements:

PHP
interface HasCorners
{
    public function corners(): int;
}
class Square extends Shape implements HasCorners
{
    public function area(): float
    {
        return $this->size ** 2;
    }
    public function corners(): int
    {
        return 4;
    }
}
  1. interface HasCorners declares one method, corners(), without a body. Interface methods are always public.
  2. Square extends Shape and implements HasCorners, so it writes both methods: area() for the parent and corners() for the interface.
  3. A class has one parent but may implement any number of interfaces: implements A, B.

Besides methods, an interface may declare constants. It never holds properties with values or ready code. Since PHP 8.4, an interface may also require a property, but such a property still has no value in the interface.

If the class lacks one of the interface's methods, PHP stops the script with a fatal error at the class declaration:

TEXT
Fatal error: Class Square contains 1 abstract method and must therefore be declared abstract or implement the remaining method (HasCorners::corners)

Abstract class or interface

This question often comes up in a PHP interview. You can keep the answer in mind as a table:

Abstract classInterface
Properties with valuesallowednot allowed
Methods with a bodyallowednot allowed
How many per classone, through extendsany number, through implements
An object through newnot allowednot allowed

Use an abstract class when a family of classes shares data and code. Use an interface when different classes need the same ability, but each has its own code for it.

instanceof and polymorphism

Let's add a circle and look at the shapes together:

PHP
class Circle extends Shape
{
    public function area(): float
    {
        return 3.14 * $this->size ** 2;
    }
}

$sq = new Square(3);
foreach ([$sq, new Circle(1)] as $shape) {
    echo $shape->describe(), '; '; // Square 9; Circle 3.14;
}
echo "\n";
var_dump($sq instanceof Shape); // bool(true)
var_dump(new Circle(1) instanceof HasCorners); // bool(false)

Let's go through what it printed:

  1. The loop calls the same describe() on every shape, and each shape computes its area in its own way. This is the polymorphism from the previous lesson: the loop code does not know whether it holds a square or a circle.
  2. The square's area() returns 9.0 of type float, and echo prints such a number without the .0, as 9.
  3. instanceof checks whether an object belongs to a class or an interface. $sq instanceof Shape gives true even though $sq is a Square object: the check walks the whole chain of parents and all the interfaces.
  4. Circle does not implement HasCorners, so the second answer is false. When the left side of instanceof is not an object, the answer is false too, not an error.

Here the job description analogy falls short. A person may be able to do everything it lists without ever signing it. In PHP, instanceof HasCorners gives true only for a class that wrote implements HasCorners: having a corners() method is not enough.

Common mistake

Trying to create an object of an abstract class:

PHP
$shape = new Shape(2); // ✗
TEXT
Fatal error: Uncaught Error: Cannot instantiate abstract class Shape

An abstract class is a template, and PHP does not let you build an object from it. The same goes for an interface: new HasCorners() gives Cannot instantiate interface HasCorners. The fix is to create an object of a child class, for example new Square(2).

Key points

  • An abstract class is a template: you cannot create an object of it, but it may have properties, a constructor, ready methods and abstract ones.
  • An interface lists methods without bodies; a class signs up with implements and must write every method.
  • A class has one parent, but it may implement any number of interfaces.
  • instanceof is true for the object's class, all its parents and all the interfaces it implements.