Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 8 of 8
  1. #1
    Super Moderator
    Join Date
    May 2002
    Location
    Perth Australia
    Posts
    4,040
    Thanks
    10
    Thanked 92 Times in 90 Posts

    __sleep and __wakeup with serialized object woes

    Hi, I keep a shopping cart going... ala
    PHP Code:
    class scart_madmin{
        function 
    __construct(&$smarty,&$config){
            
    $subclass='centaur_madmin';
            if(isset(
    $_SESSION[SCART_NAME]) && !empty($_SESSION[SCART_NAME])){
                
    $this->scart_obj unserialize($_SESSION[SCART_NAME]);
            }else{
                
    $this->scart_obj = new $subclass($smarty,$config);
            }
        }
        function 
    listen($req){
            return 
    $this->scart_obj->listen($req);
        }

    thats fine, a new instance is created if a current session does not hold one and that works fine... however because I am passing $smarty and $config to the shopping cart class (centaur_madmin) the serialized object gets very big, something I wanted to avoid. (it carries all of Smarty's info as well as $config which is not massive but I don't need that serialized anyway since it has little affect apart from some presentation info),

    I tried adding a sleep method to centaur_madmin..
    PHP Code:
    /*in centaur_madmin class*/
    function __construct(&$smarty,&$config){
         
    $this->smarty=$smarty;
         
    $this->config=$config;
    ...
    etc
    }
    private function 
    __sleep(){
         unset(
    $this->smarty);
         unset(
    $this->config);

    and as expected the $smarty and $config are gone from the serialized object, but as I expected the object will not wake up properly I assume due to the missing $smarty and $config

    I played with the __wakeup() method (using globalised versions of the smarty and config vars) but the object failed to instantiate, I kind of expected it not to work

    so , any clues how to keep the size of the serialized object down ? I see that static variables are not serialized but I cant keep an object reference ($smarty,$config) as static variables.
    resistance is...

    MVC is the current buzz in web application architectures. It comes from event-driven desktop application design and doesn't fit into web application design very well. But luckily nobody really knows what MVC means, so we can call our presentation layer separation mechanism MVC and move on. (Rasmus Lerdorf)

  • #2
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    Globalization or factory style objects if the $smarty and $config are object types are really the only way to do this. Since these are external variables that are passed at construction time, they won't be available during a wakeup of the object at least not within its scope.
    I'd try to find a way to get around using serialize at the level of a class that requires input. If not, the only way I can think of is to either create factory patterns for object's provided, or to use global if they are more primitive. A quick example with the primitive, although I can't test with the subclass this shows what I mean:
    PHP Code:
    class scart_madam
    {
        private 
    $scart_obj;
        private 
    $smartyVar;
        private 
    $configVar;

        private function 
    instantiate()
        {
            
    $smarty $GLOBALS[$this->smartyVar];
            
    $config $GLOBALS[$this->configVar];

            
    $subclass='centaur_madmin';
            
    printf('Instantiating class with smarty: %s, config: %s' PHP_EOL$smarty$config);
            
    /*if(isset($_SESSION[SCART_NAME]) && !empty($_SESSION[SCART_NAME])){
                $this->scart_obj = unserialize($_SESSION[SCART_NAME]);
            }else{
                $this->scart_obj = new $subclass($smarty,$config);
            } */
        
    }

        public function 
    __construct($smartyVar$configVar)
        {
            
    $this->smartyVar $smartyVar;
            
    $this->configVar $configVar;

            
    $this->instantiate();
        }


        public function 
    __sleep()
        {
            return array(
    'smartyVar''configVar''scart_obj');
        }

        public function 
    __wakeup()
        {
            
    $this->instantiate();
        }
    }

    $s 'smartyvar';
    $c 'configvar';

    $c1 = new scart_madam('s''c');
    print_r($c1);
    $ser serialize($c1);
    printf(PHP_EOL 'serialized: %s' PHP_EOL$ser);

    $c2 unserialize($ser);
    print_r($c2); 
    Still absolutely hate the idea of requiring a global. Not to mention all subclasses will need to do the same thing with the handling of the variables.

    Any chance that $smarty and $config are classes that have a static singleton or factory on them?

  • #3
    Super Moderator
    Join Date
    May 2002
    Location
    Perth Australia
    Posts
    4,040
    Thanks
    10
    Thanked 92 Times in 90 Posts
    Thanks for the example, playing now ...

    Quote Originally Posted by Fou-Lu
    Any chance that $smarty and $config are classes that have a static singleton or factory on them?
    not currently but thinking about it perhaps they should have, though I am assuming if its all getting to hard here then I am doing something wrong in general, I could lose the $config quite easily and will have to see how Smarty behaves as a singleton and how I can fit that in.... give me a bit of time to play .. I am going to need more help
    resistance is...

    MVC is the current buzz in web application architectures. It comes from event-driven desktop application design and doesn't fit into web application design very well. But luckily nobody really knows what MVC means, so we can call our presentation layer separation mechanism MVC and move on. (Rasmus Lerdorf)

  • #4
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    Doesn't even need to be a singleton, but a simply getintance would certainly help.
    PHP Code:

    class C
    {
        private 
    $yourvars;
        private 
    $oSmarty;
        private 
    $oConfig;

        public function 
    __construct()
        {
            
    $this->initialize();
        }
        private function 
    initialize()
        {
            
    $this->oSmarty Smarty::getInstance();
            
    $this->oConfig Config::getInstance();
        }

        public function 
    __sleep()
        {
            return array(
    'yourvars');
        }

        public function 
    __wakeup()
        {
            
    $this->initialize();
        }

    That would be much easier if you can. I haven't serialize in a long time myself ever since I stopped using the built in sessions and went straight for the DB approach.

  • #5
    Super Moderator
    Join Date
    May 2002
    Location
    Perth Australia
    Posts
    4,040
    Thanks
    10
    Thanked 92 Times in 90 Posts
    aha OK , sorry the delay and a slightly different question but related and need to solve this one first (if it actually needs solving)

    so I followed Fou-Lu's advice and am looking at singletons for $smarty and $config
    PHP Code:
    class Smarti extends Smarty{
      public static function 
    getInstance($newInstance null){
        static 
    $instance null;
        if(isset(
    $newInstance))
          
    $instance $newInstance;
        if ( 
    $instance == null )
          
    $instance = new Smarti();
        return 
    $instance;
      }

      public function 
    __construct(){
        
    parent::__construct();
        
    $this->plugins_dir = array(FP_FILE_ROOT.'/data/res/smarty',FPA_LIB.'/smarty/libs/plugins');
        
    $this->template_dir =FP_FILE_ROOT.'/data/tpl';
        
    //other smarty config stuff
            
    $this->assign('FP_FILE_ROOT',FP_FILE_ROOT);
            
    //etc other globally usefull stuff for my templates
      
    }

    so the question I have is... am I better off from a performance standpoint and a design standpoint to ..

    PHP Code:
    class blah{
            function 
    __construct(){
                      
    $this->smarty=new Smarti::getInstance();
            }
            function 
    other_function(){
                       
    $this->smarty->assign(//etc/
            
    }

    # OR #
    PHP Code:
    class blah{
            function 
    __construct(){
            }
            function 
    other_function(){
                       
    $smarty=new Smarti::getInstance();
                       
    $smarty->assign(//etc/
            
    }

    in other words call the static instance only when I need it or create a class variable containing a reference to it ?

    in most cases $smarty would only be used once per class though in some cases it may be used a couple of times but no more.

    Is one way better than the other ? esp with serialization in mind or is it of little consequesnce?
    resistance is...

    MVC is the current buzz in web application architectures. It comes from event-driven desktop application design and doesn't fit into web application design very well. But luckily nobody really knows what MVC means, so we can call our presentation layer separation mechanism MVC and move on. (Rasmus Lerdorf)

  • #6
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    The second would theoretically be more efficient since you don't need to store a pointer to the object. Executing directly in line with an existing function would allow you to discard the variable on completion. On the other hand, it also means more temporary variable creations.
    Passing it into the constructor IMO is still the best thing to do, but doesn't play well with serialization so you cannot use that. Then it really comes down to whether you think that the object pointer as a class member versus a local object pointer per call is a better option. The metric between the two is probably unmeasurable realistically, but I'd say you'd look at the following:
    - If its passed to the constructor, it will require more static memory (4 bytes in 32bit compiles, I think its 8 in the 64 but cannot be 100% sure).
    - If its constructed in line, you are looking at more processing time since you need to jump twice to get the pointer instead of once. The only additional memory may come down to if you actually assign a variable locally, in which case you have temp memory usage that's equivalent to the member property now.

    IMO, I'd store it as a class member, but you need to put it in a separate function and invoke it. I *think* you can actually force the constructor call within the __wakeup (via $this->__construct, but I wouldn't recommend the new call), since you need to use that to make your call to the smarty class to invoke.

    Another option that may work that I haven't considered. Instead of writing a class that relies directly on config and smarty and is serializable, have you considered writing instead a container for the serializeable class and only the container makes use of the config and smarty? It means an extra step during invokation since the serialized class doesn't know what its supposed to do and will be lost, but can instead be controlled directly by the container.
    So instead of having a Cart that is serializable which has Items, you could have a Cart that has CartItems which is serializable which has Items. Its a redundant layer, but CartItems would know nothing of configs or smarty, it would only know about Item. Cart on the other hand wouldn't be serializable, but would instead extract the CartItems from the session.
    So long as Cart is exposed the same as it is now and chains to the CartItems, this would actually probably work better then messing with extending a singleton child from an existing class it it doesn't originally support it (and less confusing).
    That would let you get around all of the issues.
    PHP Code:
    class Cart
    {
        private 
    $smarty;
        private 
    $config;
        private 
    $cartItems;
        const 
    SCART_NAME 'cart';

        public function 
    __construct(Smarty $s, array $c// don't know the datatypes sorry
        
    {
            
    $this->smarty $s;
            
    $this->config $c;
            
    $this->cartItems = !empty($_SESSION[self::SCART_NAME]) ? $_SESSION[self::SCART_NAME] : new CartItem();
        }

        public function 
    __destruct()
        {
            if (!empty(
    $this->cartItems))
            {
                
    $_SESSION[self::SCART_NAME] = $this->cartItems;
            }
        }

    Something like that perhaps?

  • #7
    Super Moderator
    Join Date
    May 2002
    Location
    Perth Australia
    Posts
    4,040
    Thanks
    10
    Thanked 92 Times in 90 Posts
    ok, I actually started with just a serialized cartItems when I first wrote the cart, and for reasons I can not recall .. [it was a while ago] expanded it to serializing the whole class.
    I still keep a separate SESSION[SESSION_NAME]['SCART_CURRENT'] which holds just the cart contents and totals independently of scart itself for quick display of the current cart contents in places that did not otherwise need to initialize the scart, I did not use a database for this (and probably still wont) since 75% of cart activity comes to nothing and sessions are so much easier to clean up than database entries.

    There is also a scart_users class which is a wrapper to whatever user backend and authentication is in place & a scart_gateway class (wrapper to various available gateways) I think this is why I decided to serialize the whole thing so I could keep track of the users and cart contents and gateway status all in one place which seemed to be a good idea at the time.

    I am now rethinking that, esp with your comments above, I am racking my brain as to why I ended up serializing the whole darn thing... I am sure there was a reason and maybe it made sense at the time.

    Thanks for you input... I will have a sit down and start sketching a rewrite in a similar fashion to your last post , why this always happen when you are working on a deadline ?
    resistance is...

    MVC is the current buzz in web application architectures. It comes from event-driven desktop application design and doesn't fit into web application design very well. But luckily nobody really knows what MVC means, so we can call our presentation layer separation mechanism MVC and move on. (Rasmus Lerdorf)

  • #8
    Super Moderator
    Join Date
    May 2002
    Location
    Perth Australia
    Posts
    4,040
    Thanks
    10
    Thanked 92 Times in 90 Posts
    Quote Originally Posted by Fou-Lu
    , have you considered writing instead a container for the serializeable class and only the container makes use of the config and smarty? It means an extra step during invokation since the serialized class doesn't know what its supposed to do and will be lost, but can instead be controlled directly by the container.
    I know this is old now but anyway

    I have ended up doing exactly the above, I an still calling my config and template classes as singletons but in a wrapper that calls rather than extends the cart class itself which is small enough to be serialized without concern.

    I think I got `extends` happy , and I am sure it seemed a good idea at the time

    PHP Code:
    class scart_ctl{
        function 
    __construct($basepath,$retpath=''){
            
    $this->basepath strpos($basepath,'?')!==false $basepath.'&' $basepath.'?' ;
            
    $this->retpath = isset($retpath)?$retpath:$baspath;
            
    $this->smarty=Smarti::getInstance();
            
    $this->config=fpa_config::getInstance();

            if(isset(
    $_SESSION[SCART_NAME])){
                
    $this->scart unserialize($_SESSION[SCART_NAME]);
            }else{
                 
    $this->scart = new fpa_scart($basepath,$retpath);
            }
                    
    //etc

    anyway thanks for all the ideas.
    resistance is...

    MVC is the current buzz in web application architectures. It comes from event-driven desktop application design and doesn't fit into web application design very well. But luckily nobody really knows what MVC means, so we can call our presentation layer separation mechanism MVC and move on. (Rasmus Lerdorf)


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •