Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

PHP 5 Преобразование в свой тип обекта

276
19 марта 2008 года
Rebbit
1.1K / / 01.08.2005
Есть иерархия классов
 
Код:
GlobalUser
   /    |    \
User Agent Company
Изначально были только User, Agent, Company которые независели друг от друга и хранились в разных таблицах и имели свои поля, которые по смыслу частично пересекались, о у полей с одним смыслом были разные названия. Доступ к полям идет через методы get_название_поля()

Теперь стоит задача обединить их в одну сущность. Сделал GlobalUser со всеми необходимыми полями. В User, Agent, Company перегрузил методы get_название_поля() так чтоб данные доставались из нужних полей GlobalUser. Ето сделано для того чтоб не переписывать кучу кода (ну типа для совместимоси с уже сделаным). Но есть проблема. Я получаю с БД сущность типа GlobalUser. Данные в ней то есть, а вот методов get_название_поля() которые перегружают доступ к полям к примеру Юзера там нет, потому что они описаны в User
Как мне привести GlobalUser к User ???

ЗЫ. Я могу написать Конструктор для User которому буду передавать GlobalUser и он с него скопируется, но ето не очень подходит :(. Хочется чтоб ето был один обект в памяти. Я понимаю что то что я делаю полный изврат, но в User Agent Company нет новых полей, только методы, которые производят дорступ к полям. Так что нарушения целосности данных не произойдет.
271
19 марта 2008 года
MrXaK
721 / / 31.12.2002
мейби в User добавить поле var $globalUser; и потом присваивать ему ссылку на объект GlobalUser?
$GlobalUser = new GlobalUser();
$User->globalUser = & $GlobalUser;
337
19 марта 2008 года
shine
719 / / 09.06.2006
Если я правильно понял и теперь нужно все данные хранить в одной таблице, то добавляйте в нее дополнительное поле где будете хранить имя класса и при создании объектов, сразу после выборки, создавайте не абстрактный Globaluser а конкретный класс имя которого вы можете прочитать в новом поле. То есть GlobalUser создавать можно, но только если в поле записи храниться название этого класса.
15
20 марта 2008 года
shaelf
2.7K / / 04.05.2005
GlobalUser В данном контексте должен использоваться как абстрактный и доступа к нему напрямую не должно быть (если он просто описывает общую сущность полей). Если ты захотел объеденить все таблицы (у тебя одна таблица на все 3 класса (Я понимаю эти классы как модель (MVC))), то нужно просто перенастроить 3 дочерних на родительскую таблицу. Приводить от GlobalUser к User возможным не представляется (извратится можно, но с любыми комментами ты через полгода сам будешь смотреть и не понимать что ты написал).
PS Обычно во всех (под всеми я наивно понимаю Java, т.к. только пых и немного Java я и знаю :)) преоброзование приводится выше по ирархии, т.е. от User к GlobalUser.
276
20 марта 2008 года
Rebbit
1.1K / / 01.08.2005
Уточняю суть дела.
Раньше под юзерами, агентами и компаниями выступали конкретные пользователи и у каждого из них были свои потребности и права по использованию сайта. Теперь начальству надо чтоб у каждого пользователя была полная функциональность, которая предоставляется етими тремя сущностями. Тоесть залогинился и виступаеш и как юзер и как агент и как компания. Плодить записи в трех таблицах и связывать их - полный изврат в котором точно ногу вывернеш.

Цитата: Mr.Hacker
мейби в User добавить поле var $globalUser; и потом присваивать ему ссылку на объект GlobalUser?
$GlobalUser = new GlobalUser();
$User->globalUser = & $GlobalUser;



Думал о таком но ету идею отбросил потому что в юзере, агенте, компании придется очень много перегружать и перенаправлять на его поле глобал юзер.
Хотя если подумать, то пожалуй может и стоит попыхтеть над модернизацией трех сущностей и етим все и обойдется. Я подумаю над етим.

[quote=shine]Если я правильно понял и теперь нужно все данные хранить в одной таблице, то добавляйте в нее дополнительное поле где будете хранить имя класса и при создании объектов, сразу после выборки, создавайте не абстрактный Globaluser а конкретный класс имя которого вы можете прочитать в новом поле. То есть GlobalUser создавать можно, но только если в поле записи храниться название этого класса.[/quote]
Совсем неприемлимо, потому что одна запись может выступать и как юзер и как агент и как компания в зависимости от контекста использования. Кроме того придется теперь использовать сам GlobalUser с полной функциональностю. Сами классы Юзер, Агент, Компания оставлены только для совместимости с предыдущим уже не маленьким кодом. (Правда етой совместимоти пока добиться не удается :) )

[quote=shaelf]GlobalUser В данном контексте должен использоваться как абстрактный и доступа к нему напрямую не должно быть (если он просто описывает общую сущность полей)[/quote]
Как уже сказал выше - неподходит, потому что и сам ГлабалЮзер будет использоваться теперь с полной функциональностю.
[quote=shaelf]нужно просто перенастроить 3 дочерних на родительскую таблицу[/quote]
Ето уже сделано. Кроме того сам ГлобалЮзер тоже настроен на ету таблицу.
[quote=shaelf]Приводить от GlobalUser к User возможным не представляется (извратится можно, но с любыми комментами ты через полгода сам будешь смотреть и не понимать что ты написал).[/quote]
Вот и не понимаю как извратиться. Создать екземпляр юзера и копийнуть туда поля глобалюзера не совсем подходит.
[quote=shaelf]преоброзование приводится выше по ирархии, т.е. от User к GlobalUser[/quote]. В сишке кажись получится. Но не уверен. Да ето изврат но может всеже стоит както провернуть.

Короче что я сейчас вижу. Либо непонятно как извращаться для приведения типа. ( shaelf подскажи как ;) ) либо делать то что предложил Mr.Hacker
Тут же и прошу совета что лутше.

271
20 марта 2008 года
MrXaK
721 / / 31.12.2002
если задача соеденить просто 3 класса, и каждый из них не будет обращаться к элементам друг друга, то по-моему мой вариант лучше... а из глобального класса уже делать с этими тремя как элементами что угодно...
15
21 марта 2008 года
shaelf
2.7K / / 04.05.2005
Собсно тогда вижу 3 выхода:
1. Если роли (я воспринимаю юзера, компанию и агента именно как роли) больше не нужны, но не хочется терять их (классы), то создавай ещё один (общий) и его юзай. Если у тебя всё же будет какое разделение (по ролям), то мне кажется проще сделать именно роли и по этим ролям подгружать данные классы.
PS ИМХО вообще, лучше объеденить в один класс...
276
21 марта 2008 года
Rebbit
1.1K / / 01.08.2005
Мда. Пожалуй буду делать агрегацию. Ето позволит роботать с юзером, агентом и компанией также как и раньше + через агрегированный (во слово сказал) обект можно доступится до самого ГлдабалЮзера если будет такая необходимость.

ЗЫ. Ето дело немного отложили так ка появилась более приоритетная задача, но как сделаю - напишу получилось или нет и сколько было проблем :)
276
21 марта 2008 года
Rebbit
1.1K / / 01.08.2005
УРА. Заделал.
Короче сокращенная история.
Я уже розказывал на форуме когдато что сделал себе на РНР5 псевдопроперти. Реализовал ето в родительском почти для всего классе
Код:
abstract class Entity extends BaseClass {
       
        function __set($Name, $Value)
        {
            if (method_exists($this, 'set_'.$Name)) {
                return call_user_func(array(&$this, 'set_'.$Name), $Value);
            }
            else {
                return parent::__set($Name, $Value);
            }
        }

        function __get($Name)
        {
            if (method_exists($this, 'get_'.$Name)) {
                return call_user_func(array(&$this, 'get_'.$Name));
            }
            else {
                return parent::__get($Name);
            }
        }
       
    }
Что получается. Если есть паблик поле, то обращение к нему идет напрямую, если поле прайвет протектед или его вообще нет то обращаться к нему можно так какбудто оно есть, но в класе надо написать методы доступа get_/set_название поля.

Дальше надо было сделать сайт на 3 языках Ну с шаблонами проблем нет. Смарти поддержывает такое. А как быть с сущностями в БД.
Написал еще класс MLEntity extends Entity. Код не привожу потомучто большой и непонятный.
Суть в БД столбцы "поле__язык". Там тоже все через __гет __сет. А используем поле как обичное. Тоесть $instance->field. А уж тогда MLEntity смотрит что field многоязычний и решает на каком языке его возращать и устанавливать.
Дальше поверх него стоит еще класс который умеет роботать со своими числовыми полями как с текстовыми строчками определенными в таблице-словаре в БД.
Ето все особо к сути не относится. Просто чтоб видно было что ето все уже достаточно запутано, зато очень удобно и функционально

Тоесть так
Entity
|
MLEntity
|
DictEntity
|
GlobalUser

На каждом уровне наследывания кроме GlobalUser перегружаются __get/__set

Теперь надо синхронизировать поля в User с полями в GlobalUser.
Для етого в User пишем чтото типа
 
Код:
public function get_pname(){
            return $this->p_pname;
        }
С помощю Entity я могу написать
echo $user->pname
и получу значение из $user->p_pname
С предыдущим кодом какбы совместили если б не приведения типов о котором я спрашивал.
276
21 марта 2008 года
Rebbit
1.1K / / 01.08.2005
Делать агрегацыю в трех сущностях юзера, агента и компании - я ленивый. Решил сделать класс Прокси от которого пронаследую User Agent Company
Код:
class ProxyUser extends DictEntity implements IDBEntity{
       
        public $global_user; // агрегированый глобальный юзер
        private $refClass;   // ревлектор для глобального юзера
        private $nativeRefClass; // рефлектор для себя тоесть для потомка
        // которым будет User Agent или Company
        // нужно чтоб знать наш ли ето метод или метод агрегированого прокси
       
        public function ProxyUser(){
            parent::MLEntity(array());
            $this->global_user = new GlobalUser();
            $this->refClass = new ReflectionClass('GlobalUser');
            // смотрим кто мы get_class($this)
            $this->nativeRefClass = new ReflectionClass(get_class($this));
        }
       
        // нужно чтоб посмотреть наш ли псевдопроперти или агрегата
        protected function is_native_property($Name){
            return
                $this->nativeRefClass->hasMethod('get_'.$Name) ||
                $this->nativeRefClass->hasMethod('set_'.$Name);
        }
       
        function __set($Name, $Value){
            if ($this->is_native_property($Name))
                // если псевдопроперти наш то роботаем с ним через DictEntity MLEntity Entity
                return parent::__set($Name, $Value);
            else
                // если не наш то передаем управление агрегату
                return $this->__set_proxy($Name, $Value);
        }

        function __get($Name){
            if ($this->is_native_property($Name))
                return parent::__get($Name, $Value);
            else
                return $this->__get_proxy($Name);
        }
       
        function __call($Name, $Args){
            $this->__call_proxy($Name, $Args);
        }

        function __set_proxy($Name, $Value)
        {
            if ($this->refClass->hasProperty($Name))
                $prop = $this->refClass->getProperty($Name);
            // если ето реальное поле то роботаем с ним
            if ($prop && $prop->isPublic()){
                $prop->setValue($this->global_user, $Value);
            }
            else {
            // если ето не поле то наверное псевдопроперти и роботаем с ним
            // если не псевдопроперти то ошибка вылезет внутри
                return $this->global_user->__set($Name, $Value);
            }
        }

        function __get_proxy($Name)
        {
            if ($this->refClass->hasProperty($Name))
                $prop = $this->refClass->getProperty($Name);
            if ($prop && $prop->isPublic()){
                return $prop->getValue($this->global_user);
            }
            else {
                return $this->global_user->__get($Name);
            }
        }
       
        function __call_proxy($Name, $Args)
        {
            if ($this->refClass->hasMethod($Name))
                $method = $this->refClass->getMethod($Name);
            if ($method && $method->isPublic()){
                return $method->invokeArgs($this->global_user, $Args);
            }
            else {
                $this->global_user->__call($Name, $Args);
            }
        }
........................      
    }
И теперь вуаля.
 
Код:
class User extends ProxyUser{
       
        public function User() {
            parent::ProxyUser();
        }
       
        public function get_fname(){
            return $this->p_fname;
        }
Нет ни одного своего поля.
fname - псевдопроперти которое связано с p_fname (тут p_ не от слова "пропертя" а от слова "персона")
Самого p_fname тоже нет. Оно будет доставаться из агрегата.

Если кому хватило терпения прочитать и понять, то я оч благодарен за внимание.

ЗЫ. ИМХО Ето у меня уже достаточно серйозний набор классов имеется. Подумываю может получится продать ну или хоть опенсурсом выложить. Только вот документацию писать лень.

PSS
Приводить ГлобалЮзера к Юзеру надо примерно так
 
Код:
$global_user = new GlobalUser();
$user = new User();
$user->global_user = $global_user;
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог