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.
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)
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();
}
}
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
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)
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.
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?
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)
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.
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 ?
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)
, 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();
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)