Магический метод __set вызывается при попытке изменить значение несуществующего или скрытого свойства.
В качестве параметров он принимает имя свойства и значение, которое ему пытаются присвоить.
Давайте посмотрим на практическом примере. Пусть у нас дан вот такой класс Test:
<?php
class Test
{
private $prop1;
private $prop2;
}
?>
Давайте сделаем в этом классе магический метод __set, который с помощью функции var_dump будет выводить имя свойства, к которому произошло обращение, и значение, которое этому свойству пытаются установить:
<?php
class Test
{
private $prop1;
private $prop2;
public function __set($property, $value)
{
var_dump($property . ' ' .$value);
}
}
?>
Параметры $property и $value могут иметь любое название. Главное, чтобы они вообще были. В эти параметры PHP будет передавать имя свойства (в первый параметр) и значение (во второй параметр).
Проверим работу нашего класса:
<?php
$test = new Test;
$test->prop = 'value'; // var_dump метода __set выведет 'prop value'
?>
Давайте теперь будем устанавливать значение свойству, имя которого хранится в переменной $property:
<?php
class Test
{
private $prop1;
private $prop2;
public function __set($property, $value)
{
$this->$property = $value; // устанавливаем значение
}
}
?>
Теперь мы сможем записывать в приватные свойства снаружи класса:
<?php
$test = new Test;
$test->prop1 = 1; // запишем 1
$test->prop2 = 2; // запишем 2
?>
Записывать мы можем, однако, проверить, записалось ли туда что-то - нет, так как свойства приватные.
Можно сделать геттер для этих свойств или просто воспользоваться магическим методом __get. Воспользуемся вторым вариантом:
<?php
class Test
{
private $prop1;
private $prop2;
public function __set($property, $value)
{
$this->$property = $value;
}
// Магический геттер свойств:
public function __get($property)
{
return $this->$property;
}
}
?>
Вот теперь мы можем проверить работу нашего класса. Проверим:
<?php
$test = new Test;
$test->prop1 = 1; // запишем 1
$test->prop2 = 2; // запишем 2
echo $test->prop1; // выведет 1
echo $test->prop2; // выведет 2
?>
На самом деле, конечно же, не стоит разрешать всем подряд записывать в приватные свойства, иначе пропадает суть этих приватных свойств (проще сделать их публичными и все).
Поэтому данный метод следует применять только тогда, когда в этом действительно есть необходимость. Ниже мы еще рассмотрим примеры удачного применения.
Несуществующее свойство
Давайте попробуем записать данные в несуществующее свойство - это будет работать:
<?php
$test = new Test;
$test->prop3 = 3; // запишем 3
echo $test->prop3; // выведет 3
?>
Пусть мы не хотим разрешать записывать в несуществующие свойства. И, вообще, хотим разрешить запись только в свойства prop1 и prop2.
Это легко сделать - достаточно в методе __set добавить соответствующее условие:
<?php
class Test
{
private $prop1;
private $prop2;
public function __set($property, $value)
{
// Напишем условие:
if ($property == 'prop1' or $property == 'prop2') {
$this->$property = $value;
}
}
public function __get($property)
{
return $this->$property;
}
}
?>
Если таких свойств будет много, то не очень удобно перечислять их все в условии.
Давайте запишем разрешенные для записи свойства в массив и будем проверять наличие свойства в этом массиве с помощью функции in_array:
<?php
class Test
{
private $prop1;
private $prop2;
public function __set($property, $value)
{
$properties = ['prop1', 'prop2']; // разрешенные свойства
if (in_array($property, $properties)) {
$this->$property = $value;
}
}
public function __get($property)
{
return $this->$property;
}
}
?>
Проверка при записи
Давайте будем проверять значения свойств на соответствие определенному условию:
<?php
class Test
{
private $prop1;
private $prop2;
public function __set($property, $value)
{
switch($property) {
case 'prop1':
// Если prop1 от 0 до 10:
if ($value > 0 and $value < 10) {
$this->$property = $value;
}
break;
case 'prop2':
// Если prop2 от 10 до 20:
if ($value > 10 and $value < 20) {
$this->$property = $value;
}
break;
default:
// Такого свойства нет
break;
}
}
public function __get($property)
{
return $this->$property;
}
}
?>
Применение
Практическое применение метода __set вы изучите самостоятельно, решив вот такую задачу:
Пусть дан вот такой класс User с геттерами и сеттерами свойств:
<?php
class User
{
private $name;
private $age;
public function getName()
{
return $this->name;
}
public function setName($name)
{
if ($name != '') { // проверяем имя на непустоту
$this->name = $name;
}
}
public function getAge()
{
return $this->age;
}
public function setAge($age)
{
if ($age >= 0 and $age <= 70) { // проверяем возраст
$this->age = $age;
}
}
}
?>
Переделайте код этого класса так, чтобы вместо геттеров и сеттеров использовались магический методы __get и __set.
Возможно, после переделки код нашего класса стал немного запутаннее, но иногда, когда проверка присваиваемых свойствам значений одинакова или чем-то похожа такой прием может немного сократить и улучшить ваш код.