#php #inheritance #abstraction
#php #наследование #абстракция
Вопрос:
В следующем коде PHP будет недоволен тем, что customMethod() является закрытым. Почему это так? Видимость определяется тем, где что-то объявлено, а не определено?
Если бы я хотел сделать customMethod видимым только для шаблонного кода в классе Template и предотвратить его переопределение, я бы просто сделал его защищенным и окончательным?
Template.php:
abstract class Template() {
abstract private function customMethod();
public function commonMethod() {
$this->customMethod();
}
}
CustomA.php:
class CustomA extends Template {
private function customMethod() {
blah...
}
}
Main.php
...
$object = new CustomA();
$object->commonMethod();
..
Комментарии:
1. Я знаю, что это пример кода, но, пожалуйста, снимите скобки с
abstract class Template()
Ответ №1:
Абстрактные методы не могут быть частными, потому что по определению они должны быть реализованы производным классом. Если вы не хотите, чтобы это было public
, это должно быть protected
, что означает, что это могут видеть производные классы, но никто другой.
В руководстве по PHP по абстрактным классам приведены примеры использования protected
таким образом.
Комментарии:
1. Это отличается от того, как ведет себя C (и я думаю, Java). C позволяет чисто виртуальным функциям (их эквиваленту абстрактных функций) быть частными. Это хорошо, потому что позволяет производному классу указывать и контролировать, ЧТО делать, обеспечивая при этом, чтобы только базовый класс мог выбирать, КОГДА это делать. Защищенные абстрактные функции не могут дать вам такую же гарантию, поскольку производный класс может свободно создавать общедоступную функцию, которая вызывает защищенную реализацию и нарушает инкапсуляцию.
2. Обходной путь: вы можете добавить
final
ключевое слово к защищенной функции в определении абстрактного класса (т.е.final protected function my_function()
). Это предотвратит переопределение функции дочерними классами, хотя дочерний класс может вызывать функцию для себя (чего не может произойти с частной родительской функцией). Противоречит ли это цели определения абстрактного класса или нет, это философская дискуссия для другого дня. (В качестве альтернативы вы могли бы определить новый класс, который расширяет абстрактный класс, и определить там функцию в частном порядке.)
Ответ №2:
Если вы боитесь, что customMethod
это будет вызываться вне CustomA
класса, вы можете создать CustomA
класс final
.
abstract class Template{
abstract protected function customMethod();
public function commonMethod() {
$this->customMethod();
}
}
final class CustomA extends Template {
protected function customMethod() {
}
}
Комментарии:
1. Краткий ответ с вспомогательным кодом. Поскольку в этой теме есть два вопроса, и только один из них рассматривается в принятом ответе, я также поддержал этот ответ.
Ответ №3:
Ничто в PHP, которое является закрытым в дочернем классе, не видно родительскому классу. Ничто из частного в родительском классе не видно дочернему классу.
Помните, что при использовании абстрактных методов в PHP видимость должна передаваться от дочернего класса к родительскому классу. Использование видимости private
в этом сценарии с PHP полностью инкапсулировало CustomA::customMethod
бы внутри CustomA
. Вашими единственными вариантами являются public
или protected
видимость.
Поскольку вы не можете создать экземпляр абстрактного класса Template
, конфиденциальность от клиентского кода сохраняется. Если вы используете final
ключевое слово, чтобы предотвратить расширение будущих классов CustomA
, у вас есть решение. Однако, если вам необходимо расширить CustomA
, вам пока придется смириться с тем, как работает PHP.
Комментарии:
1. Хорошее подробное объяснение. Поскольку в этой теме есть два вопроса, и только один из них рассматривается в принятом ответе, я также поддержал этот ответ. Это не предоставляет код, подобный @nikksan, но он подробно объясняет, почему PHP ведет себя так, как он. Я искал механизм «контракта» в PHP, чтобы гарантировать, что производные классы последовательно реализуют частные функции для улучшения ремонтопригодности. Это не может быть сделано AFAIK с интерфейсом. Использование защищенных методов в конечном дочернем классе, по-видимому, служит этой цели. Этот ответ объясняет процесс.
Ответ №4:
Абстрактные методы являются общедоступными или защищенными. Это обязательно.