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

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

    ?>

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open