Pull to refresh

Не статичные статические члены класса

Здравствуйте. Вы думаете, что в заголовке автор решил поумничать? Пошутить? Покаламбурить? Отнюдь. Просто на днях ему пришлось решать одну задачу, в которой он (т.е. я) столкнулся с одним, как оказалось, не совсем удобным свойством статических членов классов. Собственно речь идет о многих языках програмирования, но т.к. проблема возникла при написании приложения на языке php, то и все дальнейшие рассуждения будут приводиться применительно к нему, но всё изложенное можно так же транспонировать и на другие языки програмирования. Итак…

Сижу я вечером дома. Пишу небольшое приложение тесно связанное с базами данных.

Приложение, как я написал, небольшое, но с довольно серьезной бизнес-логикой и сложными данными. Естественное мое решение — использовать ORM для работы с mysql. И, так-как время позволяло, решил воплотить в жизнь давно вынашиваемую идею-создать собствееное очень маленькое и легкое ORM (в результате автор изменил задачу и написал просто надстройку над redbeansPHP, в которой использовал излагаемые ниже соображерия).

Первое, что нужно сделать в любой ORM — сопоставить класс таблице базы данных. Конечно, самое подходящее место для этого-статическое свойство класса. Почему именно статическое? А потому, что все объекты данного класса используют значение этого свойства.

Вроде бы все логично, но не так все просто. Представьте ситуацию, когда объекты наследуются от одного и того же предка (в данном случае в этом предке реализованы общие методы для работы с БД в выражениях создаваемой ORM).

Пусть общий предок всех классов class CProtoObject.

class CProtoObject{
   protected static $_tableName;
   .......
  public static function setClassTable($p_tableName){
   self::$_tableName=$p_tableName;
 }
}

И есть два его потомка: class CUser extends CProtoObject и CFlat extends CProtoObject, которые хранят данные в таблицах tbl_user и tbl_flat, соответственно.

Чтобы задать имена таблиц используем вызов статического метода setClassTable:

CUser::setClassTable("tbl_user");
CFlat::setClassTable("tbl_flat");

Некоторые читатели уже увидели проблему: Оба класса обращаются к одной и той же переменной, описанной в их общем предке CProtoObject. Т.е. объекты обоих классов будут записывать свои данные в tbl_flat, т.к. эта таблица указана для свойства _tableName последней. Суть прблемы: бывают случаи, когда значения статического свойства предка и наследника или двух наследников должны быть разными.

CUser::$_tableName!=CFlat::$_tableName!=CProtoObject::$_tableName

Для решения этой проблемы я пошел следующим путем: создал статическую переменную типа массив в классе предке для всех наших классов CProtoObject:

protected static $_staticValues=array();

И статический метод:

public static setTable($p_tableName){
   static::$_staticValues[static::class]=$p_tableName;
}

Тогда, для сохранения имен таблиц для каждого класса достаточно вызвать этот метод:

CUser::setTable("tbl_user");
CFlat::setTable("tbl_flat");

А вот метод получения имени таблицы для класса:

public static function getTableOfClass(){		return static::$_staticValues[static::class];	
}

Вот и все. Не правда ли, что вышеизложенное немного напоминает работу компилятора при составлении деревьев виртуальных функций? В заключении уточню: для хранения нескольких статических переменных можно использовать в качестве параметра метода setTableName любой агрегатный тип, например, массив. Все вышеизложенные соображения я воплотил в одном классе CStaticPropValues (файл CStaticPropValues.php). Чтобы использовать вышеописааный функционал, объект данного класса достаточно добавить в любой Ваш класс. Пример использования можно увидеть в файле index.php.

Оба файла можно найти на github
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.