Как проинитить данные класса из сериализированного представления объекта?

xintrea

Новичок
Как проинитить данные класса из сериализированного представления объекта?

Здравствуйте!

Хочется мне вот чего. Есть у меня "хранилище" объектов. В этом хранилище лежат сериализованные копии объектов. Я пользуюсь фреймверком CodeIgniter, и хочу чтобы объекты контроллеров "восстанавливали" свое состояние.

Выглядеть это должно примерно так:

Код:
class Menu extends Controller
{

 private $menu_counter=0;
 private $menu_pointer=0;

 function __constructor()
 {
  ...
 
  $objectdata=$stack->get_objectdata();

  if($objectdata!=NULL) $this=unserialize($objectdata);
 }
 ...
}
Но конечно, так использовать $this нельзя. Получается ошибка:

Код:
Cannot re-assign $this in menu.php on line 28
Я, конечно, могу сделать методы, возвращающие массив свойств, и устанавливающие свойства из массива. И работать через них. Но эти методы нужно будет постоянно контролировать в каждом классе контроллера, и менять их, если появилось/удалилось/переименовалось какое-нибудь свойство. А это потенциальный источник ошибок.

Вопрос. Как проинициализировать свойства класса "изнутри" класса, имея сериализованную копию объекта данного класса?
 

MiksIr

miksir@home:~$
Вообще-то сериализация умеет сериализовать именно объекты. Т.е.
$menu = new Menu();
$string = serialize($menu);
$menu = unserialize($string);
А для каких-то служебных действий внутри объекта перед сереиализациией и после восстановления есть служебные методы __sleep и __wakeup
 

xintrea

Новичок
Код:
$menu = new Menu();
$string = serialize($menu);
$menu = unserialize($string);
Это ты показал, как создать объект с заполнением из сериализованных данных "извне". А нужно "изнутри".

А для каких-то служебных действий внутри объекта перед сереиализациией и после восстановления есть служебные методы __sleep и __wakeup
На пальцах можно объяснить, как ими можно воспользоваться?
 

Beavis

Banned
xintrea
конечно можно) *указывает пальцем в сторону мануала*
 

MiksIr

miksir@home:~$
http://www.php.net/manual/en/language.oop5.magic.php

А какую структуру из себя представляет $objectdata? Сериализованный объект или сериализованный массив с данными?
 

xintrea

Новичок
http://www.php.net/manual/en/language.oop5.magic.php
Это я читал.

А какую структуру из себя представляет $objectdata? Сериализованный объект или сериализованный массив с данными?
Сериализованный объект.

Я уже хотел было хранить не сериализованный объект, а воспользоваться внутри класса конструкцией

Код:
get_class_vars(__CLASS__)
http://docs.php.net/manual/en/function.get-class-vars.php

чтоб получить список всех свойств. Cделать базовый класс с методами

save_property()
restore_property()

которые используют эту конструкцию, и наследоваться от него. Чтоб восстановить данные, можно былоб просто вызывать restore_property() из конструктора.

Но вовремя вспомнил, что иногда пользуюсь статическими переменными внутри каких-нибудь методов. Эти переменные, само собой, не входят в свойства класса, и информация о них передаваться/сохраняться не будет. Информация о состоянии таких переменных сохраняется только при сериализации объекта.

Так что вопрос "как проинитить данные класса внутри класса, имея сериализованную копию" остается открытым.
 

dimagolov

Новичок
Так что вопрос "как проинитить данные класса внутри класса, имея сериализованную копию" остается открытым.
ты страдаешь фигней ставя вопрос таким образом.
но есть и для тебя простое решение:
PHP:
$clone= unserialize($string);
$clone->copyTo($this); // метод придется написать
 

dimagolov

Новичок
xintrea, думать самому совсем лень?
PHP:
function copyTo($dest) {
   ...
   $dest->prop= $this->prop;
   ...
}
 

xintrea

Новичок
xintrea, думать самому совсем лень?

function copyTo($dest) {
...
$dest->prop= $this->prop;
...
}
Ну так это копирование только свойств объекта. Я же написал

"Но вовремя вспомнил, что иногда пользуюсь статическими переменными внутри каких-нибудь методов. Эти переменные, само собой, не входят в свойства класса, и информация о них передаваться/сохраняться не будет. Информация о состоянии таких переменных сохраняется только при сериализации объекта."

Как быть в вашей схеме со статическими переменными внутри методов?

-~{}~ 03.11.09 00:06:

Вопрос, видимо, сводится к тому, можно ли внутри класса дать такие команды, чтобы $this указывало на нужную копию объекта. Что это будут за команды?
 

john.brown

просто кулибин
xintrea
$this всегда указывает "сам на себя", т.е. текуший объект. И заменить его другим объектом нет никакой возможности. Делай вокруг своих объектов декоратор, в котором и прописывай что то вроде:
PHP:
class ObjectDecorator {
    private $instance = NULL;
    
    public function __construct($objdata) {
        $this->instance=unserialize($objdata);
    }
}
Ну и дальше __get(), __set(), __call() тебе в руки... ж)
 

zerkms

TDD infected
Команда форума
а уже была описана задача, которая заставляет реализовывать подобный изврат?
 

xintrea

Новичок
Автор оригинала: john.brown
xintrea
$this всегда указывает "сам на себя", т.е. текуший объект. И заменить его другим объектом нет никакой возможности. Делай вокруг своих объектов декоратор, в котором и прописывай что то вроде:
PHP:
class ObjectDecorator {
    private $instance = NULL;
    
    public function __construct($objdata) {
        $this->instance=unserialize($objdata);
    }
}
Ну и дальше __get(), __set(), __call() тебе в руки... ж)
Проблема в том, что я пользуюсь фреймверком CodeIgnigter. И в нем классы контроллеров должны создаваться по определенной схеме

http://code-igniter.ru/user_guide/general/controllers.html

Фреймверк обращается к контроллерам, напрямую преобразуя ЧПУ URL в вызов нужного метода контроллера. И он никакого $objdata декоратору контроллера всеравно не передаст.

$objdata становится известно _внутри_ объекта контроллера. Потому и нужно, чтоб объект мог восстановить сам себя из сериализованной копии.
 

john.brown

просто кулибин
xintrea
Ну и что мешает внутри обертки-контроллера узнать $objdata, восстановить объект, и дальше ему делегировать все вызовы обертки?

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

xintrea

Новичок
Автор оригинала: john.brown
xintrea
Ну и что мешает внутри обертки-контроллера узнать $objdata, восстановить объект, и дальше ему делегировать все вызовы обертки?
Каким кодом ты предлагаешь делегировать все вызовы обертки? Так чтоли

Код:
class ObjectDecorator { 
    private $instance = NULL; 
     
    public function __construct($objdata) { 
        $this->instance=unserialize($objdata); 
    } 

   public function show($param) {
     $this->instance->show($param);
   }

   public function edit($param1, $param2) {
     $this->instance->edit($param1, $param2);
   }

   public function move($from, $to) {
     $this->instance->move($from, $to);
   }
}
Так это дублирование кода, постоянно следить за соответсвием имен и параметров вызовов. Обезьянья работа. Или можно как-то это дело автоматизировать?


Но согласен с предыдущими ораторами, что статические преременные внутри функций, которые должны сохранять значения между вызовами, это суп. Хотелось бы примерчик кода, где такая необходимость продемонстрирована.
Идея в том, чтоб работать в PHP как в обычном языке программирования. Это чуть ранее обсуждалось вот здесь

http://phpclub.ru/talk/showthread.php?s=&threadid=116702&rand=9

Это нужно чтобы состояние объектов не терялось от одного HTTP запроса до другого. И все работало прозрачно для самих объектов. То есть объект в конструкторе сам себя восстановил, и работаем дальше. О сессиях уже не думаем, хотя они используются автоматом при "восстановлении" состояния объекта.
 

john.brown

просто кулибин
http://phpclub.ru/faq/PHP5/Overload

-~{}~ 03.11.09 15:52:

не вижу в твоей ссылке обоснование необходимости сохранять значения статических переменных внутри функций. Вообще, стат. переменные внутри функции крайне специфическая и редко нужная вещч,а уж о сохранении их между вызовами просто ума не приложу, зачем...
Пример кода моно?

п.с. имхо, горе от плохой архитектуры...
 

xintrea

Новичок
Ага, значит складываетс я такая схема. В одном файле держать два класса.

Menu.php
Код:
// Декоратор
class Menu extends Controller
{
 private $instance = NULL; 
     
 public function __construct() { 
  parent::Controller();

  $objectdata=$stack->get_objectdata();

  if($objectdata!=NULL) $this->instance=unserialize($objectdata);
  else {
   $controller_name=__CLASS__.'Controller';
   $this->instance=new $$controller_name;
 } 

 public function __call($method, $arguments) { 
   call_user_func_array(array($this->instance, $method), $arguments)
 }
}

// Обычный контроллер CodeIgniter
class MenuController extends Controller
{
 ...
}
Вроде код декоратора можно в отдельный php файл вынести...

Код:
// Декоратор
class Menu extends Controller
{
 include(decorator.php);
}

// Обычный контроллер CodeIgniter
class MenuController extends Controller
{
 ...
}
Тогда обезьянничества почти нет... Надо попробовать.
 

xintrea

Новичок
Не, через декоратор в CI работать нельзя.

Движок каким-то образом видит, какием методы доступны в контроллере.

Если метод написан в коде контроллера, он вызывается.

А несуществующий метод движок даже не пытается вызвать, поэтому __call() не срабатывает.
 
Сверху