Ответ
Да, абстрактные классы могут содержать константы, как и обычные классы. Они полезны для определения общих для всех наследников неизменяемых значений.
Пример с разными уровнями доступа:
abstract class Animal {
// Публичная константа, доступна отовсюду
public const KINGDOM = 'Animalia';
// Защищенная константа, доступна внутри класса и наследников
protected const DEFAULT_SOUND = '...';
// Приватная константа, доступна только внутри Animal
private const SECRET_CODE = 123;
abstract public function makeSound(): void;
public function getSecret(): int {
return self::SECRET_CODE; // Доступ внутри класса
}
}
class Dog extends Animal {
public function makeSound(): void {
// Доступ к защищенной константе предка
echo self::DEFAULT_SOUND;
// echo self::SECRET_CODE; // Fatal error: приватная константа недоступна
}
}
// Использование
echo Animal::KINGDOM; // 'Animalia'
echo Dog::KINGDOM; // 'Animalia' (публичная константа наследуется)
$dog = new Dog();
echo $dog->getSecret(); // 123 (доступ через публичный метод предка)
Важно: константы класса (включая абстрактные) нельзя переопределять в дочерних классах.
Ответ 18+ 🔞
А, ну это вообще классика, ебать мои старые костыли! Сидишь такой, пишешь свой абстрактный класс, а потом думаешь: "А не засунуть ли мне сюда какую-нибудь константу, чтобы наследники не ебались и знали, как правильно жить?" И ведь можно, ёпта! Ровно так же, как и в обычном классе. Это ж просто значения, которые намертво вшиты в логику, общие для всей этой семейки.
Вот смотри, как это выглядит на практике, с разными уровнями доступа, чтобы не было потом "ой, а я думал, что эта константа приватная, а она, блядь, публичная":
abstract class Animal {
// Публичная константа, доступна отовсюду
public const KINGDOM = 'Animalia';
// Защищенная константа, доступна внутри класса и наследников
protected const DEFAULT_SOUND = '...';
// Приватная константа, доступна только внутри Animal
private const SECRET_CODE = 123;
abstract public function makeSound(): void;
public function getSecret(): int {
return self::SECRET_CODE; // Доступ внутри класса
}
}
class Dog extends Animal {
public function makeSound(): void {
// Доступ к защищенной константе предка
echo self::DEFAULT_SOUND;
// echo self::SECRET_CODE; // Fatal error: приватная константа недоступна
}
}
// Использование
echo Animal::KINGDOM; // 'Animalia'
echo Dog::KINGDOM; // 'Animalia' (публичная константа наследуется)
$dog = new Dog();
echo $dog->getSecret(); // 123 (доступ через публичный метод предка)
Видишь? Всё логично. Публичную — видно всем, как флаг на параде. Защищённую — только своим, наследникам, чтобы не светить лишнего. А приватную — вообще никому, кроме самого класса, хоть ты тресни. Но если очень хочется, можно сделать геттер, как я с getSecret(), и тогда хоть посмотреть значение, но не изменить — оно же константа, ёклмн.
И вот тут главный подвох, на котором многие обжигаются, ядрёна вошь: константы класса, даже в абстрактных, — их нельзя переопределить в дочерних классах. Вообще. Никак. Это не методы, где можно полиморфизм устроить. Это как табличка с правилами при входе в семью: "У нас царство — Animalia, и точка". Хоть ты в наследнике Dog объяви свою константу с таким же именем — не прокатит, будет конфликт. Они статически связаны с классом, где объявлены. Так что используй эту фичу с умом, для действительно общих, фундаментальных вещей. А то будет потом волнение ебать, когда окажется, что твоя "общая" константа на самом деле у каждого наследника должна быть своя.