Intereting Posts
php: составной if (игнорируется) перенаправление htaccess с переменными php: SQLSTATE Соединение не может быть выполнено, потому что целевая машина активно отказалась от него MAMP: php.ini – mbstring.http_input – Отключение для Drupal Получение данных из базы данных и использование их для заполнения формы – WordPress Как я могу остановить буферизацию вывода PHP из сообщений об ошибках? Попросите GD получить изображение из двоичной строки PHP-конструктор _construct не работает PHPUnit :: получить сообщение: ОК, но неполные или пропущенные тесты! без какой-либо информации, где это происходит Когда мы должны использовать многомодульную структуру (вместо простой структуры) в php Phalcon Формула Хаверсина с php Соединение с MySql SSL с Zend-Framework Ошибка: разрешенный размер памяти 67108864 байт исчерпан Преобразование .load (jquery) в чистый javascript Как передать массив в функцию и вернуть результаты с помощью массива

Почему односторонний доступ к функциям считается плохой привычкой?

Я вижу довольно часто (т. Е. В рамках Slim), что стиль доступа к одной функции (как в [1] ниже) устарел в пользу классических Java-ish 2-функций доступа (get / set) (как в [2] ниже) . Лично я предпочитаю меньше строк кода (в [1]) и меньше набирать (get / set), чем иметь возможность связывать вызовы сеттера, как в [3] (что я считаю ужасным).

Я что-то упускаю?

class Test { protected $body; // [1] single function accessor public function body($body = null) { if (!is_null($body)) $this->body=$body; return $this->body; } // [2] dual function accessors public function getBody() { return $this->body; } // [2] dual function accessors public function setBody($body) { $this->body=$body; //[3] ok, you could return $this for chaining } } 

Solutions Collecting From Web of "Почему односторонний доступ к функциям считается плохой привычкой?"

Являются ли Одиночные вспомогательные устройства плохими привычками?

Это не очень хорошая идея. Причины просты:

  • У них много обязанностей (настройка и получение данных). Хорошие функции несут единую ответственность и делают это хорошо.

  • Они маскируют намерение. Вы не можете посмотреть вызов метода и понять, что произойдет.

    Как вы думаете, что делает метод body() ? Ну, body – существительное. И наличие метода (который должен быть глаголом), являющегося существительным, является сбивающим с толку.

    Но что, если метод был age() . Возраст – это как глагол, так и существительное. Итак, когда вы видите $obj->age() , вы говорите, что объект дает вам свой возраст? Или вы говорите объекту, чтобы стареть сам?

    В то время как $obj->getAge() кристально понятен, что вы пытаетесь сделать. И $obj->getBody() одинаково ясен.

  • Это усложняет методы.

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

Так что да, я бы избегал этого.

Но давайте вернемся на минутку. Вместо того, чтобы задавать вопрос, являются ли «Одиночные вспомогательные устройства» плохой привычкой, давайте зададим один и тот же вопрос об аксессуарах в целом …

Являются ли поставщики аксессуаров плохой привычкой?

Мой ответ: да.

Зависит от роли объекта:

От этого зависит роль объекта и роль конкретного свойства. Это в каждом конкретном случае.

Существует множество объектов разных типов (объекты домена, службы, прокси, коллекции и т. Д.). Некоторые из них являются государственными, а некоторые – нет.

Если объект не имеет состояния, он не имеет свойств и, следовательно, мы можем его игнорировать.

Для тех объектов, которые имеют состояние, почему у них есть это состояние?

Если это потому, что они представляют государство, то государство должно быть общедоступным (не говоря о том, что собственность должна быть общедоступной, но государство должно быть подвержено внешнему миру). Таким образом, модели домена, представляющие бизнес-объекты, должны иметь государственное состояние.

 class User { public $name; } 

Но если роль объекта заключается не в представлении состояния, а в том, чтобы что-то делать с ним, то его не следует раскрывать.

 class UserMapper { protected $pdo; public function __construct(Pdo $connection) { $this->pdo = $connection; } public function findUserById($id) { ... } 

В случае картографа $pdo является случайным состоянием. Задача картографа состоит не в том, чтобы представлять данные соединения с базой данных, а в том, чтобы она работала.

Нижняя линия

Нижняя строка никогда не выставляет состояние, которое объект не представляет непосредственно.

Просто потому, что у вас есть свойство, это не значит, что вы должны его разоблачить. На самом деле, часто вы не должны раскрывать его. Это известно как « Скрытие информации» .

Зависит от типа государства:

Но как насчет типов объектов, которые с точки зрения состояния? Ну, как выясняется, существуют два основных типа состояния:

  1. Состояние приложения

    Think Configuration и тому подобное. В основном это состояние, которое не определено во время сборки, но известно во время выполнения.

    Важно отметить, что это состояние не должно меняться в ходе запроса. И это также должно быть разумно одним и тем же запросом к запросу (кроме развертываний и т. Д.).

  2. Пользовательское состояние

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

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

Мое утверждение:

Атрибуты собственности для состояния приложения плохие. Нет причин, по которым состояние приложения должно меняться в середине, поэтому нет причин, по которым вам следует распространять состояние.

Атрибуты доступа к объектам для пользователя могут быть в порядке. Но для этого есть нечто большее.

Зависит от того, что делает Accessor

В случае вашего примера:

 public function setBody($body) { $this->body=$body; } 

Вы по существу делаете $body публичной собственностью.

И нет ничего плохого в этом. Но зачем вам нужен метод? Что не так: public $body; в первую очередь?

Некоторые люди скажут: «Свойства злы, они никогда не должны быть публичными!». И это – hogwash, так как это именно то, что вы сделали с этим аксессуаром.

Теперь, если аксессуар сделал некоторую информацию для ввода (через подсказки типа) или другую логику проверки (минимальная длина и т. Д.), Тогда это совсем другая история …

Или это?

Позвольте мне привести пример.

 class Person { public $name; public $age; } 

против

 class StrictPerson { protected $name; protected $age; public function setName($name) { if (!is_string($name)) throw new BlahException(); if (strlen($name) < 10) throw new InvalidException(); $this->name = $name; } public function getName() { return $this->name; } public function setAge($age) { if (!is_int($age)) throw new .... if ($age < 0 || $age > 150) throw new ... $this->age = $age; } public function getAge() { return $this->age; } } 

Теперь должно быть ясно очевидно, что эти свойства всегда действительны. Правильно? Правильно? Правильно?

Ну нет. Что произойдет, если я создам ребенка:

 class LoosePerson extends StrictPerson { public function setName($name) { $this->name = $name; } public function setAge($age) { $this->age = $age; } } 

Внезапно вся наша проверка исчезнет. Теперь вы можете утверждать, что это было предназначено, и это проблема программиста. Или вы можете просто изменить свойства, чтобы быть private вместо этого, чтобы они всегда были действительными. Правильно? Правильно? Правильно?

Ну нет. Что произойдет, если я это сделаю:

 $a = new StrictPerson; $r = new ReflectionProperty($a, 'name'); $r->setAccessible(true); $r->setValue($a, 'Bob'); 

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

Нижняя линия

Использование аксессуаров в качестве валидаторов работает только в том случае, если вы всегда их используете. И каждый инструмент, который вы используете, всегда использует их. Такие вещи, как mysqli и PDO, Doctrine и PHPUnit, которые устанавливают свойство напрямую, а не вызывающие сеттеры, могут вызвать массовые проблемы.

Вместо этого вы можете использовать внешний валидатор:

 class PersonValidator { public function validate(Person $person) { if (!is_string($person->name)) { throw new Blah... } if (strlen($person->name) < 10) { throw new Blah... } if (!is_int($age)) throw new .... if ($age < 0 || $age > 150) throw new ... return true; } } 

Итак, являются ли поставщики аксессуаров плохими привычками?

Я утверждаю, что да, часто времена, когда они плохие привычки.

Теперь есть некоторые случаи, когда вы должны их использовать:

  • Когда вы должны представлять это состояние в интерфейсе

    Свойства не определены в интерфейсе. Поэтому, если вы должны представить, что объект предоставляет состояние в интерфейсе, вы должны использовать геттер и сеттер.

    Я настоятельно призываю вас рассмотреть, почему вы создаете интерфейс. Для простых объектов данных часто лучше полагаться на тип основного объекта (поскольку полиморфизм не может быть полезен из-за отсутствия логики для объекта данных).

  • Когда вам нужно скрыть внутреннее представление по какой-то причине.

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

Это вызывает интересный момент.

Когда вы создаете аксессор, вы никогда не должны создавать аксессуар свойств. Вместо этого вы должны создать государственный аксессор. Разница в том, что аксессоры свойств всегда должны возвращать свойство или устанавливать его).

Аксессор состояния, с другой стороны, может «подделать» его, если это необходимо. Таким образом, наш пример выше о строках строки unicode, может представлять собой строку в виде массива кодовых точек. Затем, когда вы получаете доступ к «строковому» состоянию, он преобразует массив в фактическую строку.

Объекты должны Аннотация

Если вы собираетесь использовать аксессор, это должно быть абстрактное состояние. Не представлять его.

Нижняя линия / TLDR

Аксессоры собственности – плохая привычка. Если вы сделаете это, сделайте свойства общедоступными и используйте объект validator.

Государственные аксессоры – не плохая привычка. Они весьма полезны для поддержания полезных абстракций.

Передайте все зависимые объекты в конструкторе и просто получите getters для доступа к ним, в большинстве случаев нет необходимости в сеттерах.

В дополнение к ответам @Kleskowy и @marty наилучшее возможное решение для этого похоже на следующее:

 class Test { protected $body; public function body() { $args=func_get_args(); if (count($args)==1) //simple setter $this->body=$args[0]; elseif (count($args)) //setter for an array $this->body=$args; else //getter return $this->body; } } 

Идея @ marty отлично подходит для создания массива, который эквивалентен синтаксису PHP 5.4 [] (за исключением массивов-помощников). Но все же совместим с PHP 5 до 5.3 😉 Затем вы можете написать:

 $a->body("a"); //a value $a->body(null); //set to null is possible $a->body("this","is","an","array"); //convenient way to initialize $body as an array $a->body(); //get the value