Должен ли я или не использовать методы getter и setter?

Хорошо, это действительно подтачивает меня, и я начинаю думать, что все сводится к личному выбору, а не к определенному способу быть более эффективным или писать лучший код: Должен ли я или не использовать методы getter/setter внутри проект PHP? Ответы, которые я прочитал, довольно противоречивы и не совсем подходят для PHP, который не является скомпилированным языком. Например, возьмите этот вопрос в Qaru ( "Зачем использовать геттеры и сеттеры?" ). Там есть несколько веских причин, почему я должен использовать их в своем коде, но все комментарии ребенка упоминают, как Аксессоры являются злыми и должны следует избегать, чередуясь между несколькими более тревожными комментариями, в которых упоминается, что их следует избегать полностью, потому что он "скручивает ваш код".

Все, что я получаю, это противоречивые ответы, ни одна из которых не относится к интерпретируемой среде 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;

Ответы

Ответ 1

Потому что, если реализация того, как изменяется значение, изменяется (на db), вам не нужно менять вызывающих абонентов. Другим примером является то, что вам может потребоваться выполнить некоторую проверку значения перед его настройкой.

Наличие метода позволяет перехватывать настройку/получение этой переменной, делая это, когда вам не кажется, что вам это нужно, делает ваш код более дружественным к изменению.

Получатели свойств

Языки, такие как С# и последние версии JavaScript, позволяют перехватывать чтение и запись свойств, поэтому вы можете просто использовать свойства на поддерживающих его языках.

Наблюдатели за объектами

Некоторые языки позволяют перехватывать чтение/настройку всех JavaScript Object.watch или недоступных свойств с PHP __get. Это позволяет вам реализовать геттеры и сеттеры, но вы получаете удар производительности из-за накладных расходов, которые они создают для каждого доступа к свойствам. Этот ответ говорит о других проблемах с геттерами и сеттерами. Лучшая практика: Магические методы PHP __set и __get

Getters and Setters в порядке, но...

Просто сделать шаблонные геттеры и сеттеры лучше, но почти так же плохо, как и публичные свойства. Если кто-то может изменить состояние вашего объекта (особенно с несколькими свойствами), он не будет хорошо инкапсулирован. http://cspray.github.io/2012/05/13/stop-calling-them-getters-setters.html

Ответ 2

Сообщение в блоге, которое вы связали, начинается с важного предложения (выделено мной):

Каждый getter и setter в вашем коде представляет собой отказ от инкапсуляции и создает ненужную связь.

Инкапсуляция - самая важная идея объектно-ориентированного программирования. Это, по сути, сводится к сокрытию сложности, аккуратно обертывая его внутри классов. В идеальном мире, когда вы используете класс, вам не нужно ничего знать о его внутренних действиях или его состоянии. Некоторые люди (например, автор этого блога) будут утверждать, что наличие геттеров и сеттеров уже слишком много информации о внутренностях класса. По их мнению, класс должен иметь только методы, которые позволяют нам сообщать объекту что-то делать, неважно, как оно это делает или какое состояние оно находится. Использование setter не "говорит объекту что-то делать", это сбрасывая состояние объекта снаружи.

Вместо этого:

$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);

Связанное чтение: Скажите, не спрашивайте.

Ответ 3

Один принцип ООП - это инкапсуляция. Класс отвечает за все переменные, которые содержатся внутри этого класса.

Установив общедоступную переменную, вы нарушаете этот принцип.

Создав аксессуар (сеттер), вы косвенным образом нарушаете этот принцип, предоставляя возможность изменить это значение вне класса.

Преимущество получателя заключается в том, что вызывающему методу не нужно заботиться о том, как извлекаются данные. Он знает только, что он получит ожидаемые данные и все. Здесь соблюдается принцип инкапсуляции.

Преимущество сеттера в том, что класс имеет возможность проверить новое значение перед его применением. В идеальном мире нет необходимости в аксессуарах, потому что класс может полностью управлять всеми его переменными. В реальном мире иногда вам нужно установить значение или получить его снаружи.

Лучший способ приблизиться к совершенному миру - ограничить доступ только к очень немногим переменным, которые необходимо изменить. И, если возможно, проверьте установленные значения.

В вашем примере второе решение лучше, потому что вы сохраняете один уровень в стек php. Ваш аксессор бесполезен, потому что переменная является общедоступной (так, без инкапсуляции) и не выполняет дополнительной проверки. Но когда это возможно, вам следует использовать accessor для проверки данных. Если данные не нужны нигде в вашем приложении, то не делайте никаких аксессуаров.

Ответ 4

Выбор зависит от вас. Другими важными особенностями PHP 5 для рассмотрения являются магия getter/setters:

http://www.php.net/manual/en/language.oop5.overloading.php#object.set http://www.php.net/manual/en/language.oop5.overloading.php#object.get

Магия этого заключается в том, что вы можете сделать что-то вроде следующего и решить, где получить/установить переменные, не объявляя их заранее:

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

Voila, что-то вроде этого теперь происходит автоматически:

$fee = new Foo(); $ fee- > bar = 42;

Ответ 5

Если вы не используете геттеры и сеттеры на языке, таком как 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; }
    }
}

Ответ 6

Огромная прибыль от использования геттера и сеттера - всякий раз, когда вам нужно вносить изменения, вам нужно только изменить геттер и сеттер.

Я попытаюсь объяснить с помощью примера:

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

Ответ 7

ИМО, использующий геттеры и сеттеры, является хорошей практикой и повышает читаемость кода. Помимо проверки значения при настройке, есть еще один пример, рассмотрим, есть ли u вызов getMoviesList(). Теперь этот метод get может быть реализован в любом случае, он может получить список фильмов из локального db, получить его из онлайн-сервиса и т.д. Итак, код, принимающий решение, может быть внутри этой функции. Где бы вы ни называли это, у вас нет заботы о местоположении и как он его получает. U просто получить список фильмов.