Небольшая идея о реализации геттеров и сеттеров в PHP версии > 5.4 и размышления о подходе к свойствам класса в контексте PHP.
Теория
Есть несколько способов обращения к свойствам класса:
1. Сделать их public.
2. Определить методы доступа типа getA, setA.
3. Использовать магические методы __get, __set.
Тут стоит остановиться на специфике PHP, как языка в целом. Динамическая типизация, легкий синтаксис и множество готовых решений открывают безграничные просторы для быстрого прототипирования. PHP действительно позволяет написать много работающего кода без продумывания всей архитектуры в самом начале. И это действительно важно, в современном мире бешеной конкуренции и, практически, беззащитности большинства идей. Поэтому, не стоит рассматривать конечный код PHP и сравнивать его с другими языками — нужно рассматривать весь процесс разработки.
Итак, беспечное, противоречащее канонам ООП и хорошего стиля, назначение аттрибута public нетипизированным свойствам на самом деле имеет огромное значение в первоначальной разработке архитектуры. На этом этапе мы можем с легкостью менять типы свойств объекта, или их имена, нам не нужно беспокоиться о их защите или корректности.
Также логично, что обратиться к свойству класса $a->b = 1 быстрее и короче и на этом этапе не имеет смысла создавать методы доступа (ведь пока нас не волнуют вопросы инкапсуляции — мы занимаемся творчеством).
И вот, у нас появился работающий прототип — настало время подумать о дальнейшей поддержке кода, о защите информации и других программистах. После первого этапа у нас остались классы, определились названия их свойств. И во всем проекте мы обращаемся к свойствам напрямую $a->b. Тут возникает проблема — как нам ограничить доступ к свойствам, не меняя обращения к ним везде. К сожалению, в PHP пока отсутствуют нативные решения этой проблемы. Но все же мы можем это реализовать чуть менее красиво.
Вопрос решается магическими методами __get и __set и созданием методов доступа. А для удобства разработки мы добавляем doc-комментарии к классу. В целом, практически любой объект удобно использовать по такой схеме и логично было бы вынести одинаковые части в отдельный код. До PHP 5.4 это было возможно реализовать только при помощи наследования, но практически — было невозможно из-за отсутствия множественного наследования. Да и в целом — наследовать другой класс с целью лишь вынесения общего кода нарушает логику связей объектов.
И вот, в PHP 5.4 нам подарили не геттеры и сеттеры, а трейты. Честно говоря, я не вижу много причин их использования — в основном желание воспользоваться ими говорит о плохой объектной системе проекта. Но вот некоторую не хватающую функциональность PHP они закрывают. Лично меня больше бы устроили геттеры и сеттеры.
Практика
Нижеприведенный код является небольшим примером реализации геттеров и сеттеров. При желании можно добавлять различные возможности. Главное, что с трейтами это нужно будет делать лишь в одном месте.
trait GetterSetter
{
public function __get($name)
{
$getter = 'get' . ucfirst($name);
if ( ! method_exists($this, $getter) )
{
throw new Exception('Not found getter for property - ' . $name);
}
return $this->$getter();
}
public function __set($name, $value)
{
$setter = 'set' . ucfirst($name);
if ( ! method_exists($this, $setter) )
{
throw new Exception('Not found setter for property - ' . $name);
}
$this->$setter($value);
return $this;
}
}
В классе A, свойство b контролируется нами с помощью трейта, а c пока «в свободном плаванье».
/**
*
* @property int $b
*
*/
class A
{
use GetterSetter;
/**
* @var unknown Временно любой тип значения
*/
public $c;
private $_b;
public function getB()
{
return $this->_b + 1;
}
public function setB($value)
{
if ( ! ($value === 2 || $value === 3 ) )
{
throw new Exception('Invalid value ' . $value . ' for b' );
}
$this->_b = $value - 1;
return $this;
}
}
Пример обращения к свойству.
$a = new A;
$a->b = 7;
Что еще можно сделать на основе такого трейта:
1. Свойства read-only, write-only и т.д.
2. Реализовать присвоение значение свойству в трейте, а в самом классе методы проверки типа checkB().
P.S. Ждем ваши варианты в опрос и примеры использования трейтов.
Автор: arvitaly