Абстракция класса

PHP поддерживает абстрактные классы, методы и свойства. Нельзя создавать экземпляры абстрактных классов, и класс, в котором объявили хотя бы один абстрактный метод или свойство, должен быть абстрактным. Абстрактные методы объявляют только сигнатуру и открытую или защищённую область видимости метода; абстрактным методам нельзя определять реализацию.

При наследовании абстрактного класса дочерний класс обязан определить методы, которые пометили абстрактными в объявлении родительского класса, и следовать обычным правилам наследования и совместимости сигнатуры.

Начиная с PHP 8.4 в абстрактных классах разрешили объявлять абстрактные свойства, как с открытой, так и с защищённой областью видимости. Защищённому абстрактному свойству удовлетворяет свойство, которое доступно для чтения или записи как из защищённой, так и из открытой области видимости.

Абстрактному свойству удовлетворяет либо стандартное свойство, либо свойство, для которого определили хуки, которые соответствуют операции чтения или записи абстрактного свойства.

Пример #1 Пример абстрактного метода

<?php

abstract class AbstractClass
{
    // Эти методы потребуется определить в дочернем классе
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // Общий метод
    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";

?>

Результат выполнения приведённого примера:

ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2

Пример #2 Пример абстрактного метода

<?php

abstract class AbstractClass
{
    // Абстрактному методу необходимо только определить обязательные аргументы
    abstract protected function prefixName($name);
}

class ConcreteClass extends AbstractClass
{
    // Дочернему классу разрешается определять в сигнатуре метода необязательные параметры,
    // которые не объявляли в сигнатуре метода родительского класса
    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";

?>

Результат выполнения приведённого примера:

Mr. Pacman
Mrs. Pacwoman

Пример #3 Пример абстрактного свойства

<?php

abstract class A
{
    // В дочернем классе потребуется объявить открытое для чтения свойство
    abstract public string $readable {
        get;
    }

    // В дочернем классе потребуется объявить защищённое или открытое для записи свойство
    abstract protected string $writeable {
        set;
    }

    // В дочернем классе потребуется объявить защищённое или открытое свойство с симметричной областью видимости
    abstract protected string $both {
        get;
        set;
    }
}

class C extends A
{
    // Определение удовлетворяет требованию абстрактного свойства, и делает свойство доступным для записи, что допустимо
    public string $readable;

    // Такое определение того же свойства НЕ удовлетворит требованию,
    // поскольку свойство недоступно для открытого чтения
    protected string $readable;

    // Определение на 100 % удовлетворяет требованию абстракции, поэтому такого определения достаточно.
    // Свойство доступно для записи и только из защищённой области видимости
    protected string $writeable {
        set => $value;
    }

    // Определение расширяет видимость с защищенной до общедоступной, это допустимо
    public string $both;
}

?>

Абстрактное свойство абстрактного класса должно содержать объявление по крайней мере одного абстрактного хука. При объявлении для абстрактного свойства и хука get, и хука set одному хуку в абстрактном классе разрешается предоставить реализацию, как в приведённом примере.

Пример #4 Пример абстрактного свойства

<?php

abstract class A
{
    // Определение стандартной, но переопределяемой реализации хука set,
    // и требование к дочерним классам предоставить реализацию хука get
    abstract public string $foo {
        get;

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

?>