Должен ли я или не должен использовать методы получения и установки?
Хорошо, это действительно беспокоит меня, и я начинаю думать, что все сводится к личному выбору, а не к конкретному способу повышения эффективности или написанию более качественного кода: следует или не следует использовать методы getter/setter в проекте PHP? Ответы, которые я прочитал, довольно противоречивы и не совсем подходят для PHP, который не является компилируемым языком. Например, возьмите этот вопрос о переполнении стека (" Зачем использовать геттеры и сеттеры?"). Существует ряд веских причин, по которым я должен использовать их в своем коде, но все дочерние комментарии упоминают, как Accessors являются злыми, и их следует избегать, перемежая несколько более тревожных комментариев, которые упоминают, что их следует избегать полностью, потому что это "испортил твой код".
Все, что я получаю, это противоречивые ответы, ни один из которых не имеет отношения к интерпретируемой среде PHP. Может ли кто-то пролить свет на то, почему / почему их не следует использовать в PHP, и на то, как они обосновывают это решение? Действительно ли имеет значение, можем ли мы просто определить свойство как частное или защищенное и в любом случае:
Геттеры и сеттеры для инкапсуляции очень смешные
... цитата из "sbi" (зачем использовать геттеры и сеттеры?)
Лично я до сих пор не понимаю, как:
Class Foo {
public $bar;
function setBarType($val) {
$this->bar = $val;
}
}
$fee = new Foo();
$fee->setBarType(42);
превосходит это:
Class Foo {
public $bar;
}
$fee = new Foo();
$fee->bar = 42;
7 ответов
Потому что, если реализация того, как установлено значение, меняется (на дБ), вам не нужно менять вызывающих. Другим примером является то, что вам может потребоваться проверить значение перед его установкой.
Наличие метода позволяет вам перехватывать установку / получение этой переменной, делая это, когда кажется, что вам это не нужно, и делает ваш код более дружественным к изменениям.
Собственники
Такие языки, как C# и последние версии JavaScript, позволяют вам перехватывать чтение и запись свойств, поэтому вы можете просто использовать свойства на языках, которые его поддерживают.
Наблюдатели за объектами
Некоторые языки позволяют перехватывать чтение / настройку всех JavaScript Object.watch или недоступных свойств с помощью PHP __get. Это позволяет реализовывать методы получения и установки, но вы получаете снижение производительности из-за накладных расходов, которые они создают для каждого доступа к свойству. Этот ответ говорит о других проблемах с геттерами и сеттерами. Лучшая практика: магические методы PHP __set и __get
Геттеры и сеттеры в порядке, но...
Лучше просто создавать шаблонные геттеры и сеттеры, но это почти так же плохо, как общедоступные объекты. Если кто-то может изменить состояние вашего объекта (особенно с несколькими свойствами), он не будет хорошо инкапсулирован. http://cspray.github.io/2012/05/13/stop-calling-them-getters-setters.html
Сообщение в блоге, на которое вы ссылаетесь, начинается с важного предложения (выделение добавлено)
Каждый метод получения и установки в вашем коде представляет собой неспособность инкапсулировать и создает ненужную связь.
Инкапсуляция является наиболее важной идеей объектно-ориентированного программирования. По сути, это сводится к сокрытию сложности, аккуратно оборачивая ее внутри классов. В идеальном мире, когда вы используете класс, вам не нужно ничего знать о его внутренней работе или его состоянии. Некоторые люди (например, автор этого блога) будут утверждать, что наличие методов получения и установки уже слишком много информации о внутренностях класса. По их мнению, класс должен иметь только методы, которые позволяют нам указывать объекту что-то делать, не говоря уже о том, как он это делает или в каком состоянии он находится. Использование сеттера не означает "сказать объекту что-то сделать", это гадость с состоянием объекта извне.
Вместо этого:
$a = myObject();
// Querying object state, making a decision outside the object, and changing its state
if ($a->getWarbleFizz() < 42) {
$a->setYourWarbleFizzTo(42);
}
// Gee, I hope I made the right decision...
$a->nowDoSomethingUseful();
Вы должны писать код так:
$a = myObject(42);
$a->doStuff();
Или это:
$a = myObject();
$a->doStuff(42);
Связанное чтение: Скажи, не спрашивай.
Большим преимуществом использования геттера и сеттера является то, что когда вам нужно внести изменения, вам нужно только изменить геттер и сеттер.
Я попытаюсь объяснить на примере:
protected $date;
public function getDate(){
return $this->date;
}
public function setDate($date){
$this->date = $date;
}
Представьте, что есть причина, по которой дату всегда следует увеличивать на один день. Вам придется искать во всем проекте, где вы получили доступ к вашему классу.
Но используя геттеры и сеттеры, вы можете изменить код на:
protected $date;
public function getDate(){
return $this->date;
}
public function setDate($date){
$date = new DateTime($date);
$date->modify('+1 day');
$this->date = $date;
}
Одним из основных принципов ООП является инкапсуляция. Класс отвечает за все переменные, которые содержатся внутри этого класса.
Установив публичную переменную, вы нарушаете этот принцип.
Создавая аксессор (сеттер), вы косвенно нарушаете этот принцип, давая возможность изменить это значение вне класса.
Преимущество метода получения заключается в том, что вызывающему методу не нужно заботиться о том, как извлекаются данные. Он только знает, что получит ожидаемые данные и все. Здесь принцип инкапсуляции соблюдается.
Преимущество сеттера в том, что у класса есть возможность проверить новое значение перед его применением. В идеальном мире нет необходимости в средствах доступа, потому что класс может полностью управлять всеми своими переменными. В реальном мире иногда нужно установить значение или получить его извне.
Лучший способ приблизиться к идеальному миру - ограничить аксессоров только несколькими переменными, которые нужно изменить. И проверьте установленные значения, если это возможно.
Что касается вашего примера, второе решение лучше, потому что вы сохраняете один уровень в стеке php. Ваш метод доступа бесполезен, потому что ваша переменная в любом случае является общедоступной (то есть без инкапсуляции) и не выполняет никакой дополнительной проверки. Но когда это возможно, вы ДОЛЖНЫ использовать аксессор для проверки данных. Если данные не нужны больше нигде в вашем приложении, не используйте никаких методов доступа.
Если вы не используете методы получения и установки в языке, таком как PHP, который не является безопасным для типов, то как вы собираетесь гарантировать, что тип свойства объекта является правильным?
Возможно, я полностью упускаю суть, но если вам нужен доступ к свойству извне объекта, я думаю, что это по-прежнему лучший вариант для использования методов доступа...
Кроме того, как упоминает Джуон Мендес: некоторые языки предлагают вам перехватывать, когда рассматриваются сами свойства. Это также может прийти к PHP
Вы могли бы даже иметь открытый установщик и защищенный получатель:
class TimePeriod {
protected $Seconds = 3600;
public $Hours {
get { return $this->Seconds / 3600; }
set { $this->Seconds = $value * 3600; }
}
// This property is read only as there is no setter
public $Minutes {
get { return $this->Seconds / 60; }
}
/* public getter, protected setter */
public $Milliseconds {
get { return $this->Seconds * 1000; }
protected set { $this->Seconds = $value / 1000; }
}
}
Выбор остается за вами. Другими важными особенностями PHP 5, которые нужно учитывать, являются магические методы получения / установки:
http://www.php.net/manual/en/language.oop5.overloading.php http://www.php.net/manual/en/language.oop5.overloading.php
Волшебство этого в том, что вы можете сделать что-то вроде следующего и решить, где получить / установить переменные, не объявляя их заранее:
Class Foo {
private $data = array();
function __set($name,$val) {
$this->$data[$name] = $val;
}
function __get($name,$val) {
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
}
Вуаля, что-то вроде этого сейчас происходит автоматически:
$ fee = new Foo (); $ fee-> bar = 42;
IMO, использующий методы получения и установки, является хорошей практикой и также повышает читабельность кода. Помимо проверки значения при настройке, есть еще один пример, рассмотрим, если вы звоните getMoviesList()
, Теперь этот метод get может быть реализован в любом случае, он может получить список фильмов из локальной базы данных, получить его из онлайн-сервиса и т. Д. Итак, код, принимающий решение, может быть внутри этой функции. Куда бы вы ни звонили, вам все равно, где вы находитесь и как это происходит. Вы просто получите список фильмов.