Если я могу добавить свою соль несколько месяцев спустя:
Это очень не-OO иметь публичные свойства. Все должно быть инкапсулировано просто потому, что (помимо других причин) использование прямого манипулирования атрибутами не дает вам способов легкого рефакторинга или выполнения (дополнительных) контрольных проверок, когда какой-либо внешний источник изменяет поле. Например, предположим, что у вас есть класс с множеством полей, который используется в проекте несколько раз, и этот проект содержит несколько тысяч файлов; это проект, который работает и расширяется уже несколько лет. Допустим, компания меняет свою бизнес-модель или обнаружена проблема с некоторым типом данных поля, и теперь требуется некоторая проверка; будете ли вы дублировать эту проверку во всех тех тысячах исходного кода, который напрямую обращается к общедоступному члену? В PHP решение может быть простым, но не в большинстве языков программирования OO (например, Java). Дело в том, что ООП основан на инкапсуляции. Короче говоря, инкапсуляция не Создавать не только чистый код, но и очень удобный в сопровождении (не говоря уже о рентабельности и связности) код.
Ваше предложение иметь закрытый член (массив), управляемый __get/__set, хорошо. Таким образом, если вам нужна дополнительная проверка по дороге, просто создайте свой сеттер и/или ваш геттер, и это будет конец. Некоторые могут возразить, что это контрпродуктивно, поскольку автозавершение кода не может срабатывать при __get / __set. ИМХО, полагаться на завершение кода - это просто ленивое кодирование. Но опять же, наличие у каждого члена собственного геттера и/или сеттера позволяет вам написать более полную документацию по API. Лично я обычно использую этот метод для внутренних занятий или занятий общего назначения. Если все ваши поля не требуют никакой валидации, или их, как вы сказали, несколько десятков, то использование магических методов, на мой взгляд, допустимо.
Суть в том, чтобы избежать прямого доступа членов к экземплярам класса, и точка. Как вы решите достичь этого, зависит исключительно от вас. Просто убедитесь, что API хорошо документирован, чем более абстрактным вы его сделаете.
И наконец, в PHP, если у вас уже есть используемые классы, которые не инкапсулируют свои поля, например, что-то вроде
class SomeObject {
public $foo;
public $bar;
public $baz;
//...
}
вы можете просто исправить этот класс без необходимости рефакторинга чего-то вроде:
class SomeObject {
private $_foo; // having underscore as prefix helps to know what's private/protected
private $_bar; // inside the code.
private $_baz;
public function __get($name) {
$methodName = 'get'.ucfirst($name);
if (method_exists($this, $methodName)) {
return $this->{$methodName}();
} else {
throw new Exception("Method '{$methodName}' does not exist");
}
}
public function __set($name, $value) {
$methodName = 'set'.ucfirst($name);
if (method_exists($this, $methodName)) {
$this->{$methodName}($value);
} else {
throw new Exception("Method '{$methodName}' does not exist");
}
}
public function getFoo() { return $this->_foo; }
public function setFoo($value) { $this->_foo = $value; }
public function getBar() { return $this->_bar; }
public function setBar($value) { $this->_bar = $value; }
public function getBaz() { return $this->_baz; }
public function setBaz($value) { $this->_baz = $value; }
}
А потом
$obj = new SomeObject();
$obj->foo = 'Hello world'; // legacy code support
$obj->setFoo('Hello world'); // same thing, but preferred
И вы удовлетворяете как парадигме OO, так и имеете прямой доступ к атрибутам экземпляра. Вы также можете иметь __call()
проверку префикса 'get' или 'set' и вызывать __get()
и __set()
соответственно, но я бы не стал заходить так далеко, хотя это действительно позволило бы классам общего назначения получать доступ к своим закрытым членам через ->member
и ->getMember()
/->setMember()
person
Yanick Rochon
schedule
23.08.2010