Witam
Czy w PHP jest możliwy dostęp w klasie do prywatnego pola będącego tablicą, za pomocą tzw. „metod magicznych” __get i __set? Pytam, ponieważ używam wymienionych metod do uzyskiwania dostępu do pól klasy, które są typami prostymi lub obiektami i to działa całkiem przyzwoicie (wiem, że są pewne spadki wydajności ale to w chwili obecnej nie jest dla mnie kluczowe). Chciałbym niektóre utworzone przez siebie klasy wyposażyć we właściwości tablicowe. Przez pojęcie właściwości rozumiem tu mechanizm znany z języków takich jak C# czy ObjectPascal, gdzie w klasie istnieje pole, do którego dostęp odbywa się poprzez prywatne metody dostępowe (akcesory). Pozwala to np.: sprawdzać poprawność przekazywanych wartości (dla metody „set”) czy zwracać określoną wartość dla właściwości, która może nie posiadać odpowiadającego jej prywatnego pola w klasie a zwracana wartość jest np. obliczana (dla metody „get”). Żeby dobrze wyłuszczyć nurtujący mnie problem, przytoczę fragment hipotetycznej klasy:
<?php class TMyComponent { private $_count; private $_name; private $_values; public function __construct() { $this->_ http://www.php.net/count = 0; $this->_name = ""; $this->_values = http://www.php.net/array(); } public function __get($name) { $method = "get" . http://www.php.net/ucfirst($name); if (method_exists($this, $method)) { return $this->$method(); } } public function __set($name, $value) { $method = "set" . http://www.php.net/ucfirst($name); if (method_exists($this, $method)) { $this->$method($value); } } private function getCount() { return $this->_count; } private function getName() { return $this->_name; } private function setName($value) { $this->_name = value; } public function getValues($index) { $item = NULL; if ($this->isIndexValid($index)) { $item = $this->_items[$index]; } return $item; } public function setValues($index, $value) { if ($this->isIndexValid($index)) { $this->replace($index, $value); } protected function isIndexValid($index) { $result = http://www.php.net/is_int($index) && ($index < $this->_count) && ($index >= 0); } } ?>
$myObj = new TMyComponent(); ... $n = $myObj->count; $myObj->name = "abcdef";
$oldValue = $myObj->getValues(2); // odczyt z komórki prywatnego pola klasy, gdzie pole jest tablicą $myObj->setValues(2, 64); // zapis do komórki prywatnego pola klasy, gdzie pole jest tablicą
$oldValue = $myObj->values[2]; // odczyt z komórki prywatnego pola klasy, gdzie $values jest właściwością tablicową (a nie polem klasy!) $myObj->values[2] = 64; // zapis do komórki prywatnego pola klasy, gdzie $values jest właściwością tablicową (a nie polem klasy!)
class MyClass { private $values = http://www.php.net/array(); public function __set($key, $value) { $this->values[$key] = $value; } public function __get($key) { return http://www.php.net/isset($this->values[$key]) ? $this->values[$key] : null; } } // --- $obj = new MyClass(); $obj->foo = 'bar'; $var = $obj->foo; // $var = 'bar';
Szanowny kayman'ie Twoja odpowiedź niestety nie dotyka istoty opisanego przez mnie problemu. Przykład podany przez Ciebie jest bardzo popularny. Nie chodziło mi o banalny/trywialny sposób dostępu do pól klasy zgromadzonych w jednym polu jako tablicy, indeksowanej nazwami właściwości. Jeszcze raz powtórzę: jedno z pól klasy jest tablicą. Być może nieporozumienie wynika z tego, że w dokumentacji PHP występuje pojęcie właściwości, które jest błędnie użyte przez ludzi rozwijających język PHP. To co oni opisują w swoim systemie pomocy jako właściwość to jest w rzeczywistości polem klasy. Właściwości to mechanizm dostępu do pól klasy przez metody dostępowe, które są wywoływane niejawnie (nie jest to ścisła definicja, a tylko mój jak najkrótszy opis).
Ja w swoich klasach potrzebuję dostępu do komórek pola będącego tablicą w klasie, poprzez symulowanie właściwości, które by pozwalały przekazywać indeks komórki w metodach __get i __set. W językach, które wymieniłem w poprzednim poście, tj. C# czy ObjectPascal właściwości mogą być tablicowe. Oznacza to, że w tych językach metody dostępowe "get" i "set" uwzględniają dodatkowy parametr, którym jest indeks. Przykładowo w języku ObjectPascal, klasa którą w pierwszym poście przedstawiłem, miałaby następujący (zbliżony do PHP) kod:
<?php class TMyComponent { private $_count; private $_name; private $_values; public function __construct() { $this->_ http://www.php.net/count = 0; $this->_name = ""; $this->_values = http://www.php.net/array(); } public function __get($name, $index) // <- hipotetyczny parametr "index" w metodzie __get { $method = "get" . http://www.php.net/ucfirst($name); if (method_exists($this, $method)) { if http://www.php.net/isset($index) { return $this->$method($index); } else return $this->$method(); } } public function __set($name, $value, $index) // <- hipotetyczny parametr "index" w metodzie __set { $method = "set" . http://www.php.net/ucfirst($name); if (method_exists($this, $method, $index)) { if http://www.php.net/isset($index) { $this->$method($index, $value); } else $this->$method($value); } } private function getCount() { return $this->_count; } private function getName() { return $this->_name; } private function setName($value) { $this->_name = value; } public function getValues($index) { $item = NULL; if ($this->isIndexValid($index)) { $item = $this->_items[$index]; } return $item; } public function setValues($index, $value) { if ($this->isIndexValid($index)) { $this->replace($index, $value); } } protected function isIndexValid($index) { $result = http://www.php.net/is_int($index) && ($index < $this->_count) && ($index >= 0); } } ?>
$myObj = new TMyComponent(); ... $n = $myObj->count; $myObj->name = "abcdef"; $oldValue = $myObj->values[2]; // odczyt z komórki właściwości, nie z pola klasy, gdzie niejawnie jest wywoływana czytająca metoda dostępowa $myObj->values[2] = 64; // zapis do komórki właściwości, nie do pola klasy, gdzie niejawnie jest wywoływana zapisująca metoda dostępowa
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)