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

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

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

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

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

Недвижимость

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

Объектные наблюдатели

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

Getters и Setters в порядке, но …

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

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

Каждый 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); 

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

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

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

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

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

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

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

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

Большая прибыль от использования геттера и сеттера – всякий раз, когда вам нужно вносить изменения, вам нужно только модифицировать геттер и сеттер.

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

 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

У вас может быть даже публичный сеттер и защищенный геттер:

 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 для рассмотрения являются магия getter / seters:

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;

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