Per espandere la risposta di Berry, l'impostazione del livello di accesso su protected consente a __get e __set di essere utilizzati con proprietà dichiarate esplicitamente (quando si accede al di fuori della classe, almeno) e la velocità è notevolmente più lenta, citerò un commento da un'altra domanda su questo argomento e proponi comunque di utilizzarlo:
Sono d'accordo che __get è più lento per una funzione get personalizzata (facendo le stesse cose), questo è 0,0124455 il tempo per __get () e questo 0,0024445 è per get () personalizzato dopo 10000 cicli. - Melsi 23 novembre 12 alle 22:32 Best practice: PHP Magic Methods __set e __get
Secondo i test di Melsi, considerevolmente più lento è circa 5 volte più lento. Questo è decisamente molto più lento, ma si noti anche che i test mostrano che è ancora possibile accedere a una proprietà con questo metodo 10.000 volte, contando il tempo per l'iterazione del ciclo, in circa 1/100 di secondo. È considerevolmente più lento rispetto agli effettivi metodi get e set definiti, e questo è un eufemismo, ma nel grande schema delle cose, anche 5 volte più lento non è mai effettivamente lento.
Il tempo di elaborazione dell'operazione è ancora trascurabile e non vale la pena considerarlo nel 99% delle applicazioni del mondo reale. L'unico momento in cui dovrebbe essere davvero evitato è quando accederai effettivamente alle proprietà più di 10.000 volte in una singola richiesta. I siti ad alto traffico stanno facendo qualcosa di veramente sbagliato se non possono permettersi di lanciare alcuni server in più per mantenere in esecuzione le loro applicazioni. Un annuncio di testo di una sola riga nel piè di pagina di un sito ad alto traffico in cui la velocità di accesso diventa un problema potrebbe probabilmente pagare per una farm di 1.000 server con quella riga di testo. L'utente finale non si batterà mai le dita chiedendosi perché la pagina impiega così tanto tempo a caricarsi perché l'accesso alle proprietà dell'applicazione richiede un milionesimo di secondo.
Dico questo parlando come sviluppatore proveniente da un background in .NET, ma i metodi di acquisizione e impostazione invisibili per il consumatore non sono un'invenzione di .NET. Semplicemente non sono proprietà senza di loro, e questi metodi magici sono la grazia salvifica degli sviluppatori di PHP anche per chiamare la loro versione delle proprietà "proprietà". Inoltre, l'estensione Visual Studio per PHP supporta intellisense con proprietà protette, con quel trucco in mente, penso. Penso che con un numero sufficiente di sviluppatori che utilizzano i metodi magic __get e __set in questo modo, gli sviluppatori PHP regolerebbero il tempo di esecuzione per soddisfare la comunità degli sviluppatori.
Modifica: in teoria, le proprietà protette sembravano funzionare nella maggior parte delle situazioni. In pratica, risulta che molte volte vorrai usare i tuoi getter e setter quando accedi alle proprietà all'interno della definizione di classe e delle classi estese. Una soluzione migliore è una classe di base e un'interfaccia per l'estensione di altre classi, quindi puoi semplicemente copiare le poche righe di codice dalla classe di base nella classe di implementazione. Sto facendo un po 'di più con la classe base del mio progetto, quindi non ho un'interfaccia da fornire in questo momento, ma ecco la definizione di classe ridotta non testata con proprietà magiche che ottengono e impostano usando la riflessione per rimuovere e spostare le proprietà in un array protetto:
class Component {
protected $properties = array();
public function __get($name) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
return $this->properties[$name]->value;
}
}
public function __set($name, $value) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
$this->properties[$name]->value = $value;
}
}
function __construct() {
$reflected_class = new ReflectionClass($this);
$properties = array();
foreach ($reflected_class->getProperties() as $property) {
if ($property->isStatic()) { continue; }
$properties[$property->name] = (object)array(
'name' => $property->name, 'value' => $property->value
, 'access' => $property->getModifier(), 'class' => get_class($this));
unset($this->{$property->name}); }
$this->properties = $properties;
}
}
Mi scuso se ci sono bug nel codice.