В версии PHP 5 мы получили возможность использовать конструктор класса, специальную функцию, объявляемую в классе, которая служит для инициализации экземпляра объекта. К сожалению, конструкторы, как и остальные методы класса в PHP, не могут быть «перегружены». Как это обойти, далее в статье.
Конструктор класса в PHP.
Конструктор объявляется как метод класса с именем __construct(). Он может содержать произвольное число параметров, и предназначен, прежде всего, для инициализации свойств создаваемого экземпляра объекта.
Пример функции-конструктора.
1 2 3 4 5 6 |
class MyClass { public function __construct($name) { $this->name = $name; } ... } |
Иногда классу требуется объявить несколько разных конструкторов. Здесь можно применять разные подходы, весь перечень их ограничен лишь вашей фантазией. Я покажу вам несколько вариантов.
Перегрузка конструктора класса в PHP.
В таких языках как Си, перегрузка возможна за счет типизации входных параметров. Компилятор может отличить несколько функции с разными множествами вх. параметров (по количеству и по типу). В PHP мы объявляем только имя переменной, с которой функции может быть передано что угодно. Да и число параметров при вызове функции может быть иным, так устроен PHP.
Но мы можем анализировать актуальное число параметров, их тип, и запускать нужные ветки инициализации. Так мы получим нужный конструктор класса.
Смотрим соответствующие примеры.
Разное число параметров.
Если конструкторы должны отличаться только числом параметров, то это может выглядеть вот так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class MyClass { function __construct() { $a = func_get_args(); $i = func_num_args(); swicth ($i) { case 1: //инициализация объекта, если передан только 1 параметр break; case 2: //инициализация объекта, если переданы 2 параметра break; ... case N: //инициализация объекта, если передано N параметров break; default: //инициализация в прочих не ясных ситуациях } } } |
В комментариях онлайн версии документации на php.net видел пример, где множественный выбор заменяют на вызов соответствующих методов класса.
Разные типы входных параметров.
PHP отличает скаляр от массива, массив от объекта и объекты разных типов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class MyClass { function __construct($param) { if (is_scalar($param)) { //если входной параметр - скаляр } else if (is_array($param)) { //если на входе - массив } else if (is_object($param)) { //если на входе - объект switch(get_class($param)) { case 'className1': break; case 'className2': break; ... } } } } |
Использование статических методов.
Это более универсальный подход. Мне он нравится тем, что мы можем использовать «говорящие» названия методов, создавая объект тем или иным способом. Легче читать программу, когда в названии вызываемой функции содержится дополнительная информация. Не нужно обращать внимание на число входных параметров и держать в голове типы этих переменных.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
class MyClass { // конструкторы /* Штатный конструктор мы объявляем как защищенный метод, хотя это не обязательно. Экземпляры класса создаются вызовом соответствующих статических функций. */ protected function __construct() { // общий код для всех конструкторов } static function createFromScalar($param) { //создаём экземпляр $obj = new MyClass(); //далее идет инициализация для случая, //когда параметр - скаляр ... //возвращаем экземпляр класса return $obj; } static function createFromArray($param) { //создаём экземпляр $obj = new MyClass(); //далее идет инициализация для случая, //когда переданный параметр - массив ... //возвращаем экземпляр класса return $obj; } } //теперь вместо $obj = new MyClass($param) вы пишите, например: $obj = MyClass::createFromScalar($param); |
Так вы объявляете необходимое кол-во статических методов и используете их как конструкторы класса.
Использование дочерних классов.
Перегрузка внутри класса не доступна, но мы можем перегружать конструктор в дочерних классах. Перегрузить можно только public методы. Конструктор родителя вызывается с префиксом parent::.
1 2 3 4 5 6 7 8 9 10 11 12 |
class MyClass { public function __construct($a) { echo 'parent class...'; } } class MyClass_sub extends MyClass { public function __construct($a) { parent::__construct(); echo 'sub class...'; } } |
Мне этот подход не нравится, потому что приходится плодить дочерние классы только для того, чтобы добавить ещё один конструктор. Но такая техника пригодится в более сложных случаях.
P.S.
Вариаций действительно много, что говорит о гибкости PHP. Приведенные примеры могут подтолкнуть вас придумать ещё один, лично только вам подходящий способ.
Спасибо! полезная статья.
Вот за это спасибо!!! Вы позволили мне не потерять время.
Статья отличная. Я не знаю ООП, но не сдается ли вам, что такие «трюки» говорят об урезанности ООП в PHP и в итоге это выливается в говнокод (ни в коем случае не критикую автора, просто философствую) ?
Наговнокодить можно и на Джава
PHP довольно специфичный язык, со своей узкой нишей применения, и он развивается именно исходя из этого. А итоговое качество кода — это субъективное понятие, которое может применятся к любым языкам.