Здравствуйте. Вы думаете, что в заголовке автор решил поумничать? Пошутить? Покаламбурить? Отнюдь. Просто на днях ему пришлось решать одну задачу, в которой он (т.е. я) столкнулся с одним, как оказалось, не совсем удобным свойством статических членов классов. Собственно речь идет о многих языках програмирования, но т.к. проблема возникла при написании приложения на языке php, то и все дальнейшие рассуждения будут приводиться применительно к нему, но всё изложенное можно так же транспонировать и на другие языки програмирования. Итак…
Сижу я вечером дома. Пишу небольшое приложение тесно связанное с базами данных.
Приложение, как я написал, небольшое, но с довольно серьезной бизнес-логикой и сложными данными. Естественное мое решение — использовать ORM для работы с mysql. И, так-как время позволяло, решил воплотить в жизнь давно вынашиваемую идею-создать собствееное очень маленькое и легкое ORM (в результате автор изменил задачу и написал просто надстройку над redbeansPHP, в которой использовал излагаемые ниже соображерия).
Первое, что нужно сделать в любой ORM — сопоставить класс таблице базы данных. Конечно, самое подходящее место для этого-статическое свойство класса. Почему именно статическое? А потому, что все объекты данного класса используют значение этого свойства.
Вроде бы все логично, но не так все просто. Представьте ситуацию, когда объекты наследуются от одного и того же предка (в данном случае в этом предке реализованы общие методы для работы с БД в выражениях создаваемой ORM).
Пусть общий предок всех классов class CProtoObject.
И есть два его потомка: class CUser extends CProtoObject и CFlat extends CProtoObject, которые хранят данные в таблицах tbl_user и tbl_flat, соответственно.
Чтобы задать имена таблиц используем вызов статического метода setClassTable:
Некоторые читатели уже увидели проблему: Оба класса обращаются к одной и той же переменной, описанной в их общем предке CProtoObject. Т.е. объекты обоих классов будут записывать свои данные в tbl_flat, т.к. эта таблица указана для свойства _tableName последней. Суть прблемы: бывают случаи, когда значения статического свойства предка и наследника или двух наследников должны быть разными.
Для решения этой проблемы я пошел следующим путем: создал статическую переменную типа массив в классе предке для всех наших классов CProtoObject:
И статический метод:
Тогда, для сохранения имен таблиц для каждого класса достаточно вызвать этот метод:
А вот метод получения имени таблицы для класса:
Вот и все. Не правда ли, что вышеизложенное немного напоминает работу компилятора при составлении деревьев виртуальных функций? В заключении уточню: для хранения нескольких статических переменных можно использовать в качестве параметра метода setTableName любой агрегатный тип, например, массив. Все вышеизложенные соображения я воплотил в одном классе CStaticPropValues (файл CStaticPropValues.php). Чтобы использовать вышеописааный функционал, объект данного класса достаточно добавить в любой Ваш класс. Пример использования можно увидеть в файле index.php.
Оба файла можно найти на github
Сижу я вечером дома. Пишу небольшое приложение тесно связанное с базами данных.
Приложение, как я написал, небольшое, но с довольно серьезной бизнес-логикой и сложными данными. Естественное мое решение — использовать 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