Class Abstraction

PHP has abstract classes, methods, and properties. Classes defined as abstract cannot be instantiated, and any class that contains at least one abstract method or property must also be abstract. Methods defined as abstract simply declare the method's signature and whether it is public or protected; they cannot define the implementation. Properties defined as abstract may declare a requirement for get or set behavior, and may provide an implementation for one, but not both, operations.

When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child class, and follow the usual inheritance and signature compatibility rules.

As of PHP 8.4, an abstract class may declare an abstract property, either public or protected. A protected abstract property may be satisfied by a property that is readable/writeable from either protected or public scope.

An abstract property may be satisfied either by a standard property or by a property with defined hooks, corresponding to the required operation.

Example #1 Abstract method example

<?php

abstract class AbstractClass
{
    // Force extending class to define this method
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // Common method
    public function printOut()
    {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue()
    {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix)
    {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue()
    {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix)
    {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1();
$class1->printOut();
echo $class1->prefixValue('FOO_'), "\n";

$class2 = new ConcreteClass2();
$class2->printOut();
echo $class2->prefixValue('FOO_'), "\n";

?>

The above example will output:

ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

Example #2 Abstract method example

<?php

abstract class AbstractClass
{
    // An abstract method only needs to define the required arguments
    abstract protected function prefixName($name);
}

class ConcreteClass extends AbstractClass
{
    // A child class may define optional parameters which are not present in the parent's signature
    public function prefixName($name, $separator = ".")
    {
        if ($name == "Pacman") {
            $prefix = "Mr";
        } elseif ($name == "Pacwoman") {
            $prefix = "Mrs";
        } else {
            $prefix = "";
        }

        return "{$prefix}{$separator} {$name}";
    }
}

$class = new ConcreteClass();
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";

?>

The above example will output:

Mr. Pacman
Mrs. Pacwoman

Example #3 Abstract property example

<?php

abstract class A
{
    // Extending classes must have a publicly-gettable property
    abstract public string $readable {
        get;
    }

    // Extending classes must have a protected- or public-writeable property
    abstract protected string $writeable {
        set;
    }

    // Extending classes must have a protected or public symmetric property
    abstract protected string $both {
        get;
        set;
    }
}

class C extends A
{
    // This satisfies the requirement and also makes it settable, which is valid
    public string $readable;

    // This would NOT satisfy the requirement, as it is not publicly readable
    protected string $readable;

    // This satisfies the requirement exactly, so is sufficient.
    // It may only be written to, and only from protected scope
    protected string $writeable {
        set => $value;
    }

    // This expands the visibility from protected to public, which is fine
    public string $both;
}

?>

An abstract property on an abstract class may provide implementations for any hook, but must have either get or set declared but not defined (as in the example above).

Example #4 Abstract property example

<?php

abstract class A
{
    // This provides a default (but overridable) set implementation,
    // and requires child classes to provide a get implementation
    abstract public string $foo {
        get;

        set {
            $this->foo = $value;
        }
    }
}

?>