Se posso aggiungere il mio granello di sale alcuni mesi dopo:
E 'molto non-OO per avere proprietà pubbliche. Tutto dovrebbe essere incapsulato, semplicemente perché (tra le altre ragioni) l'uso della manipolazione diretta degli attributi non fornisce metodi per eseguire facilmente il refactoring o eseguire (più) controlli di controllo quando alcune fonti esterne modificano il campo. Ad esempio, supponiamo di avere una classe con molti campi che vengono utilizzati più volte in un progetto e che il progetto contiene diverse migliaia di file; è un progetto che è in corso e ampliato da alcuni anni. Diciamo che la società sta cambiando il suo modello di business, o che si riscontra un problema con alcuni tipi di dati del campo e ora è necessario avere qualche convalida; duplicherete quella convalida in tutte quelle migliaia di codice sorgente che accede direttamente al membro pubblico? In PHP, la soluzione potrebbe essere semplice, ma non nella maggior parte del linguaggio di programmazione OO (ad esempio Java). Il fatto è che OO è based on encapsulation. In breve, l'incapsulamento non produce solo codice pulito, ma anche codice altamente manutenibile (per non dire economico e coeso).
Il tuo suggerimento di avere un membro privato (array) manipolato da __get/__set è buono. In questo modo, se hai bisogno di una validazione extra lungo la strada, crea semplicemente il tuo setter e/o il tuo getter e sarà la fine di esso. Qualcuno potrebbe obiettare che è controproducente dato che il completamento del codice non può dare il via a __get/__set. IMHO, basandosi sul completamento del codice è semplicemente codifica pigro. Ma poi di nuovo, avere ogni membro ha il proprio getter e/o setter consente di scrivere una documentazione API più completa. Personalmente, di solito uso la tecnica per le classi interne o molto generali. Se tutti i tuoi campi non richiedono alcuna convalida, o ci sono come hai detto diverse decine di loro, allora usare i metodi magici sarebbe accettabile, secondo me.
La linea di fondo è di evitare l'accesso diretto ai membri sulle istanze di classe, punto. Il modo in cui decidi di ottenerlo dipende esclusivamente da te. Assicurati che l'API sia ben documentata, più l'astrazione lo fai.
In una nota finale, in PHP, se si dispone già le classi che vengono utilizzati che non sono incapsulare i loro campi, per esempio qualcosa come
class SomeObject {
public $foo;
public $bar;
public $baz;
//...
}
si può semplicemente risolvere questa classe senza dover refactoring nulla con qualcosa di simile:
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; }
}
E poi
$obj = new SomeObject();
$obj->foo = 'Hello world'; // legacy code support
$obj->setFoo('Hello world'); // same thing, but preferred
E soddisfi sia il paradigma OO che l'accesso diretto agli attributi di un'istanza. Si potrebbe anche avere __call()
assegno per il prefisso 'get' o 'set' e chiamare __get()
e __set()
di conseguenza, ma non vorrei arrivare a tanto, anche se questo sarebbe davvero abilitare le classi di uso generale per l'accesso che i membri privati tramite ->member
e ->getMember()
/->setMember()
Quindi, come definiresti personalmente il metodo getter? Usereste '__get'? –