Translate: 
EnglishFrenchGermanItalianPolishPortugueseRussianSpanish

Obiektowe PHP: Implementacja getterów i setterów znanych z języka C#

Każdy, kto choć raz przyjrzał się językowi C#, mógł zauważyć, że posiada on możliwość deklarowania konkretnych getterów oraz setterów dla właściwości obiektu, np w taki sposób:

public class Person
{
    //default constructor 
    public Person()
        {
        }
 
    private string _Name;
    public string Name
    {
        //set the person name
        set { this._Name = value; }
        //get the person name 
        get { return this._Name; }
    }
}

O ile w języku PHP udostępniono zarządzanie magicznymi zmiennymi poprzez funkcje __get() oraz __set(), to jednak rozwiązanie to ma jedną wielką wadę. Zmienne magiczne nie są widoczne z poziomu kodu PHP (w ramach deklaracji klasy), ani z poziomu aplikacji IDE (do czasu aż zadeklaruje się je „wirtualnie” z poziomu komentarzy phpdoc).

Przedstawiam więc kolejną, mało znaną funkcjonalność języka PHP, która rozwiązuje wspomniany problem. Jest nią umagicznianie zadeklarowanych właściwości obiektu.

Oficjalnie dokumentacja języka PHP sugeruje, że metody __get(), __isset(), __unset() oraz __set() operują wyłącznie na zmiennych, które nie zostały zadeklarowane w klasie. W takim przypadku wykonanie operacji na właściwościach obiektu nie wywołuje metod magicznych.

Rzeczywistość jest jednak inna. Patrząc w kod źródłowy interpretera PHP można się szybko przekonać, że dokumentacja PHP nie jest kompletna. Istnieje jedna, jedyna możliwość zmuszenia interpretera, by wykorzystał magiczne metody na zadeklarowanych właściwościach klasy. Momentem tym jest faza konstruowania obiektu.

Poniżej przedstawiam przykładowy kod zabezpieczający przed modyfikacją wszystkie właściwości obiektu zaczynające się od znaku podkreślnika.

class Test
{
	public $_magic = "readonly";
 
	protected $realMagic = array();
 
	public function __construct() {
		foreach($this as $name => $value) {
			if($name[0] === '_') {
				$this->realMagic[$name] = $value;
				unset($this->$name);
			}
		}
	}
 
	public function __get($name) {
		if(isset($this->realMagic[$name])) {
			return $this->realMagic[$name];
		}
	}
 
	public function __set($name, $value) {
		if(isset($this->realMagic[$name])) {
			throw new Exception('This property is read only');
		}
	}
}

Pozostało nam tylko sprawdzić wyniki jego działania, robimy więc prosty test:

$x = new Test();
 
echo "<br>READING _magic PROPERTY... ";
 
echo $x->_magic;
 
echo "<br>SETTING _magic PROPERTY...<br>";
 
$x->_magic = "test";

Po wykonaniu skryptu naszym oczom ukazuje się taki wynik:

READING _magic PROPERTY... readonly
SETTING _magic PROPERTY...
 
Fatal error: Uncaught exception 'Exception' with message 'This property is read only' in C:\Documents and Settings\agraniszewski\Pulpit\www\example2.php:26 Stack trace: #0 C:\Documents and Settings\agraniszewski\Pulpit\www\example2.php(39): Test->__set('_magic', 'test') #1 {main} thrown in C:\Documents and Settings\agraniszewski\Pulpit\www\example2.php on line 26

Największym plusem tego rozwiązania jest to, że możemy w ten sposób symulować stałe obiektu/zmienne tylko do odczytu, oraz fakt, że aplikacje IDE bez problemu podpowiadają nam właściwości obiektów podczas pisania kodu.

Dodaj odpowiedź