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

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
};
}
}

?>