Эти методы срабатывают при обращении к несуществующим или недоступным полям класса или его предка. Они должны быть объявлены со спецификатором доступа public. При этом метод __get вызывается при попытке считать значение скрытого или несуществующего свойства. В качестве параметра он принимает строку, содержащею имя свойства к которому произошла попытка обратиться. Возвращаемое этим методом значение будет воспринято как значение свойства, к которому произошло обращение, при этом неважно скрыто это свойство, или оно вовсе не существует.
class Point { private $x; private $y; public function __construct($x, $y) { $this->x = $x; $this->y = $y; } public function __get($name) { echo "Произошло обращение к свойству $name "; return $this->$name; } } $p = new Point(8, 16); echo "x: $p->x "; echo "y: $p->y "; echo "Несущесвующие поле: $p->nonexistentProperty";
Произошло обращение к свойству x x: 8 Произошло обращение к свойству y y: 16 Произошло обращение к свойству nonexistentProperty Несуществующие поле:
Как видите, метод __get при такой реализации при обращении к несуществующему свойству возвращает значение null, которое в нашем примере преобразовалось к пустой строке.
Метод __set вызывается при попытке изменить значение несуществующего или скрытого свойства. В качестве параметров он принимает имя свойства и значение, которое ему пытаются присвоить. Добавим этот метод в наш класс Point.
class Point { private $x; private $y; public function __construct($x, $y) { $this->x = $x; $this->y = $y; } public function __get($name) { echo "Произошло обращение к свойству $name
"; return $this->$name; } public function __set($name, $value) { $this->$name = $value; echo "Cвойству $name присвоено значение $value "; } }
Теперь при каждой попытке изменить значение скрытого или несуществующего свойства будет выводиться соответствующее сообщение.
$p = new Point(8, 16); $p->x = 10; $p->y = 20; $p->z = 30;
Cвойству x присвоено значение 10 Cвойству y присвоено значение 20 Cвойству z присвоено значение 30
Методы __get и __set полезны тем, что с их помощью можно эмулировать наличие свойства, которого нет. При этом можно сделать так, что не заглядывая внутрь класса, об этом нельзя будет никак догадаться. Например, у нас есть класс, описывающий квадрат с одним скрытым полем, которое содержит длину стороны квадрата (side).
class Squere { private $side; public function __construct($a) { $this->side = $a; } }
Эмулируем наличие у этого класса свойства «площадь» (area). При этом учтём, что площадь квадрата и длина его стороны зависят друг от друга.
class Squere { private $side; public function __construct($a) { $this->side = $a; } public function __set($name, $value) { if ($name == 'area') { $this->setArea($value); } else if ($name == 'side') { $this->side = $value; } } public function __get($name) { if ($name == 'area') { return $this->getArea(); } else if ($name == 'side') { return $this->side; } } private function getArea() { return $this->side * $this->side; } private function setArea($area) { return $this->side = sqrt($area); } }
Теперь экземпляры этого класса будут вести себя так, словно свойство area присутствует в классе, а свойство side доступно извне.
$squere = new Squere(25); echo $squere->area; // 25 * 25 = 625
При этом нам не нужно будет заботиться о том, что площадь квадрата зависит от длины его стороны.
$squere = new Squere(10); echo $squere->side; // 10 $squere->area = 25; echo "После изменения площади изменилась и сторона:
". "$squere->side"; // 5 = sqrt(25)