Свойства ======== В PHP, переменные-члены класса называются *свойства*. Эти переменные являются частью объявления класса и используются для хранения состояния объектов этого класса (т.е. именно этим отличается один экземпляр класса от другого). На практике вам часто придётся производить чтение и запись свойств особым образом. Например, вам может понадобиться обрезать строку при её записи в поле `label`. Для этого вы *можете* использовать следующий код: ```php $object->label = trim($label); ``` Недостатком приведённого выше кода является то, что вам придется вызывать функцию `trim()` во всех местах, где вы присваиваете значение полю `label`. Если в будущем понадобится производить еще какие-либо действие, например преобразовать первую букву в верхний регистр, вам придётся изменить каждый участок кода, где производится присваивание значения полю `label`. Повторение кода приводит к ошибкам и его необходимо избегать всеми силами. Что бы решить эту проблему, в Yii был добавлен базовый класс [[yii\base\Object]] который реализует работу со свойствами через *геттеры* и *сеттеры*. Если вашему классу нужна такая возможность, необходимо унаследовать его от [[yii\base\Object]] или его потомка. > Информация: Почти все внутренние классы Yii наследуются от [[yii\base\Object]] или его потомков. Это значит, что всякий раз, когда вы встречаете геттер или сеттер в классах фреймворка, вы можете обращаться к нему как к свойству. Геттер — это метод, чьё название начинается со слова `get`. Имя сеттера начинается со слова `set`. Часть названия после `get` или `set` определяет имя свойства. Например, геттер `getLabel()` и/или сеттер `setLabel()` определяют свойство `label`, как показано в коде ниже: ```php namespace app\components; use yii\base\Object; class Foo extend Object { private $_label; public function getLabel() { return $this->_label; } public function setLabel($value) { $this->_label = trim($value); } } ``` В коде выше геттер и сеттер реализуют свойство `label`, значение которого хранится в private свойстве `_label`. Свойства, определенные с помощью геттеров и сеттеров, можно использовать как обычные свойства класса. Главное отличие в том, что когда происходит чтение такого свойства, вызывается соответствующий геттер, при присвоении значения такому свойству запускается соответствующий сеттер. Например: ```php // Идентично вызову $label = $object->getLabel(); $label = $object->label; // Идентично вызову $object->setLabel('abc'); $object->label = 'abc'; ``` Свойство, для которого объявлен только геттер без сеттера, может использоваться *только для чтения*. Попытка присвоить ему значение вызовет [[yii\base\InvalidCallException|InvalidCallException]]. Точно так же, свойство для которого объявлен только сеттер без геттера может использоваться *только для записи*. Попытка получить его значение так же вызовет исключение. Свойства, предназначенные только для чтения, встречаются не часто. При определении свойств класса при помощи геттеров и сеттеров нужно помнить о некоторых правилах и ограничениях: * Имена таких свойств *регистронезависимы*. Таким образом, `$object->label` и `$object->Label` — одно и то же. Это обусловлено тем, что имена методов в PHP регистронезависимы. * Если имя такого свойства уже используется переменной-членом класса, то последнее будет иметь более высокий приоритет. Например, если в классе `Foo` объявлено свойство `label`, то при вызове `$object->label = 'abc'` будет напрямую изменено значение свойства `label`. А метод `setLabel()` не будет вызван. * Свойства, объявленные таким образом, не поддерживают модификаторы видимости. Это значит, что объявление геттера или сеттера как public, protected или private никак не скажется на области видимости свойства. * Свойства могут быть объявлены только с помощью *не статичных* геттеров и/или сеттеров. Статичные методы не будут обрабатываться подобным образом. Возвращаясь к проблеме необходимости вызова функции `trim()` во всех местах, где присваивается значение свойству `label`, описанной в начале этого руководства, функцию `trim()` теперь необходимо вызывать только один раз — в методе `setLabel()`. При возникновении нового требования о возведение первой буквы в верхний регистр, можно быстро поправить метод `setLabel()` не затрагивая остальной код. Эта правка будет распространяться на все присвоения значения свойству `label`.