PHPAbstract Classes

Abstract Classes

Sometimes a base class exists purely to be extended — it captures shared structure and shared logic, but on its own it doesn't represent a complete, usable thing. A generic Shape has an area, but "a shape" with no further detail can't actually compute one; only a concrete shape like a Rectangle or Circle can. PHP's abstract keyword lets you say exactly that: this class defines a template other classes must finish, and it should never be instantiated by itself.

abstract class and abstract function

An abstract Shape base class

PHP
<?php
abstract class Shape {
    // No body — every concrete subclass must supply its own.
    abstract public function area(): float;

    // A regular, fully-implemented method, shared by all subclasses.
    public function describe(): string
    {
        return sprintf('%s with area %.2f', static::class, $this->area());
    }
}

class Rectangle extends Shape {
    public function __construct(
        private float $width,
        private float $height,
    ) {
    }

    public function area(): float
    {
        return $this->width * $this->height;
    }
}

$rect = new Rectangle(4, 5);
echo $rect->describe(), "\n";
Rectangle with area 20.00
`Shape` mixes two kinds of members: `area()` is declared `abstract` with no `` body at all — it's a promise, not an implementation. `describe()` is a normal method with a real body, and every subclass gets it for free. This is the point of an abstract class: it can hold as much shared, working code as you want, alongside the specific pieces it deliberately leaves undefined.
An abstract class can never be instantiated directly

Because Shape::area() has no implementation, PHP has no idea what (new Shape())->area() should even do — so it refuses to let you create a bare Shape at all.

Attempting to instantiate an abstract class

PHP
<?php
abstract class Shape {
    abstract public function area(): float;
}

$shape = new Shape();
PHP Fatal error: Uncaught Error: Cannot instantiate abstract class Shape
This is a fatal Error, not a warning
There is no way to suppress this or work around it by leaving out the abstract methods — it is intrinsic to the class being `abstract`. The only way to get a usable object is to extend the class and implement everything it left abstract.
Every concrete subclass must implement the abstract methods

If a subclass doesn't implement every abstract method it inherits, PHP requires that subclass to also be declared abstract — it can't quietly ignore the obligation and still be instantiable.

A subclass that forgets area() must stay abstract

PHP
<?php
abstract class Shape {
    abstract public function area(): float;
}

// Missing area() — this line alone would be a fatal error unless
// Triangle is also marked abstract:
abstract class Triangle extends Shape {
    public function __construct(
        protected float $base,
        protected float $height,
    ) {
    }
    // area() still not implemented — Triangle stays abstract on purpose,
    // perhaps waiting for RightTriangle / EquilateralTriangle to finish it.
}

class RightTriangle extends Triangle {
    public function area(): float
    {
        return 0.5 * $this->base * $this->height;
    }
}

$t = new RightTriangle(6, 4);
echo $t->area(), "\n";
12

Triangle is a legitimate middle layer: it adds shared fields ($base, $height) without yet committing to a formula for area, because that formula genuinely differs between a right triangle and an equilateral one. Only RightTriangle, which supplies area(), can actually be instantiated.

Abstract classes can still have constructors and properties

It's a common misconception that an abstract class is "just a list of method signatures." It can have real properties, a real constructor, and fully-implemented methods — the only requirement is that it contains at least one abstract method (or is deliberately marked abstract even with none, though that's rare in practice). Shape::describe() above already demonstrated this: it's a working method that every subclass inherits unchanged.

Abstract class vs. interface

Both an abstract class and an interface let you demand that other classes implement certain methods, which raises the natural question of when to reach for which. Use an abstract class when your subclasses genuinely share implementation and state, and the relationship is a real "is-a" hierarchy — Rectangle and RightTriangle really are shapes, and they benefit from inheriting describe() for free. Reach for an interface (covered on its own page) instead when you only need to guarantee a contract — "this object can compute an area," full stop — across classes that may be otherwise unrelated and share no implementation at all. A useful rule of thumb: if you catch yourself writing an abstract class where every method is abstract and there's no shared state, that's usually an interface wearing the wrong hat.

  • abstract class cannot be instantiated with new — doing so is a fatal Error.

  • abstract function methodName(): ReturnType; has no body; it is a contract the subclass must fulfill.

  • A subclass that does not implement every inherited abstract method must itself be declared abstract.

  • Abstract classes can still hold real properties, constructors, and fully-implemented methods alongside their abstract ones.

  • Choose an abstract class for shared implementation plus a real is-a hierarchy; choose an interface for a pure contract across unrelated classes.

static::class vs self::class
The `describe()` example used `static::class` rather than `self::class` so that the printed name reflects the actual runtime class (`Rectangle`) rather than always printing `Shape`. This distinction — called late static binding — matters most once methods are inherited and called through a subclass.
Tip
Reach for an abstract class the moment you notice two or more concrete classes copy-pasting the same method bodies while only one or two methods genuinely differ between them. Pull the shared code up into an abstract base, leave the differing pieces `abstract`, and each subclass shrinks down to just what actually makes it unique.