rwhite35 Posted September 25, 2015 Share Posted September 25, 2015 So I have a registry class that holds sub class instances. When the application loads a module, the registry class needs to make sub class functionality available to the module. There's an autoloader in place, I just need the class instances. A service manager should load the registry class with sub classes. Service manager RegistryClass has this prototype at the end of the process: // hash table of registry properties and classes // SiteNavigation example is one sub class RegistryClass Object( [data:RegistryClass:private] => [regList:RegistryClass:private] => Array ( [SiteNavigation] => SiteNavigation Object ( [siteConfig:protected] => [route:protected] => ) ) ) There are several MVC scripts in the module that require different things. However, when the script (ie module controller) picks up the Registry object, it's hash table (regList) is empty. // empty table, empty belly RegistryClass Object ( [data:RegistryClass:private] => [regList:RegistryClass:private] => Array ( ) ) I've tried using the built in PHP interface Serializable however, it's producing incomplete PHP objects when I call unserialize() method. Called from a module script - that looks like: $newObj = unserialize($serialized); // Registry appears fine, however, SiteNavigation is incomplete RegistryClass Object ( [data:RegistryClass:private] => [regList:RegistryClass:private] => Array ( [SiteNavigation] => __PHP_Incomplete_Class Object ( [__PHP_Incomplete_Class_Name] => SiteNavigation [siteConfig:protected] => [route:protected] => ) ) ) Here is a snip from the service manager which 1. instantiates a singleton registry class 2. instantiates the sub classes. $regObj = RegistryClass::getInstance(); // Singleton class holds instances of sub classes in hash table /* * set() method simply assigns sub class names as key and object instance as value to regList */ if(class_exists($className)) { $regObj->set($className, new $className); } /* * now serialize and assign to session, RegistryClass implements Serializable */ $_SESSION['RegistryClass'] = $regObj->serialize($regObj); It seems like the sub classes (ie SiteNavigation) doesn't serialize. Error log output only C:13:"RegistryClass":2:{N;}). Any thoughts are appreciated. Quote Link to comment https://forums.phpfreaks.com/topic/298312-serializable-class-with-sub-classes/ Share on other sites More sharing options...
Solution requinix Posted September 25, 2015 Solution Share Posted September 25, 2015 What is the code for RegistryClass::serialize and why aren't you using just serialize()? "__PHP_Incomplete_Class" means PHP couldn't load the class named. Which is SiteNavigation. Are you sure the autoloader is set up properly and gets installed before the call to unserialize()? Quote Link to comment https://forums.phpfreaks.com/topic/298312-serializable-class-with-sub-classes/#findComment-1521546 Share on other sites More sharing options...
rwhite35 Posted September 26, 2015 Author Share Posted September 26, 2015 (edited) What is the code for RegistryClass::serialize and why aren't you using just serialize()? "__PHP_Incomplete_Class" means PHP couldn't load the class named. Which is SiteNavigation. Are you sure the autoloader is set up properly and gets installed before the call to unserialize()? Thanks for the reply requinix! The way I called serialize() was incorrect - fixed that now - thanks! The service manager runs after all classes have been autoloaded and I've confirmed that I have valid objects at this point in the service manager process. Im expecting serialize() to recursively "serialize" each sub class. But when I pass $regObj through serialize(), only the parent RegistryClass is being serialized. error_log("RegistryClass Serialized: " . $RegClassSerial); // outputs C:13:”RegistryClass”:2:{N;} Here is the RegistryClass relevant code: class RegistryClass implements Serializable { private $data; private $regList = array(); /* instantiates the singleton, add sub classes to regList with set(), etc */ public function serialize() { return serialize($this->data); // where recursion is expected } public function unserialize($data) { $this->data = unserialize($data); } public function getData() { return $this->regList; } To test the theory that serialize() isn't recursively serializing each sub class, I've hacked a work around that does this manually. And here is that code: $regObj = RegistryClass::getInstance(); /* adds sub classes, see code in initial post */ $serial = serialize($regObj); /* * here's the hack to manually force serializing each sub class * by cloning the serialized string and appended the sub classes */ foreach($regObj->getData() as $obj) { if(is_a($obj, $className)) { $serial .= serialize($obj); } } $_SESSION['RegistryClass'] = $serial; The hack code produces a string that looks like: error_log("RegistryClass Sub Class Serialized: " . $serial); // RegistryClass Serialized: C:13:"RegistryClass":2:{N;}O:14:"SiteNavigation":2:{s:13:"... And finally, when the serial string from $_SESSION['RegistryClass'] is assigned and unserialized(), the parent class is picked up but not the subs. Again, no recursion. // module/view/Index.phtml $serialized = $_SESSION['RegistryClass']; // echo $serialized //C:13:”RegistryClass”:2:{N;}O:14:"SiteNavigation":2:{s:13:"*siteConfig";N;s:8:"*route";N;} $newObj = unserialize($serialized); print_r($newObj); /* * outputs * RegistryClass( * [data:RegistryClass:private] => * [regList:RegistryClass:private] => Array( ) * ) */ As you see from above, regList is empty. Where I'm expecting SiteNavigation. Thanks again for the feedback, I appreciate your insight. Edited September 26, 2015 by rwhite35 Quote Link to comment https://forums.phpfreaks.com/topic/298312-serializable-class-with-sub-classes/#findComment-1521548 Share on other sites More sharing options...
requinix Posted September 26, 2015 Share Posted September 26, 2015 Your serialize methods aren't doing anything with $regList, so that information will get lost during serialization. Drop the Serializable interface and its two methods and let PHP do what it normally would do. Serializable is only really if you want to change how serialization works. Quote Link to comment https://forums.phpfreaks.com/topic/298312-serializable-class-with-sub-classes/#findComment-1521553 Share on other sites More sharing options...
hansford Posted September 26, 2015 Share Posted September 26, 2015 Here is how object references can be saved during serialization. <?php error_reporting(E_ALL); ini_set('display_errors',1); define('br','<br />'); class RegistryClass { private $data; private $regList = array(); public function set($name,$value) { $this->regList[$name] = $value; } public function getData() { return $this->regList; } } class RegList { private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } $reg = new RegistryClass(); $a = new RegList("fred"); $reg->set('a',$a); $b = new RegList("jane"); $reg->set('b',$b); $c = serialize($reg); // doesn't work as references to other objects are lost //we can save the Registry object and the referenced objects in an array $c = array(); $c[0] = $reg; foreach($reg->getData() as $key => $value) { $c[1][$key] = $value; } // now serialize the array $d = serialize($c); // everything is saved // un-serialize the array $e = unserialize($d); // retrieve our Registry object $reg = $e[0]; // now add the instances back into the Registry object foreach($e[1] as $key => $value) { $reg->set($key,$value); } // test it out $instance = $reg->getData(); foreach($instance as $key => $value) { echo $key . ': ' . $value->getName() . br; } 1 Quote Link to comment https://forums.phpfreaks.com/topic/298312-serializable-class-with-sub-classes/#findComment-1521565 Share on other sites More sharing options...
rwhite35 Posted September 27, 2015 Author Share Posted September 27, 2015 (edited) What is the code for RegistryClass::serialize and why aren't you using just serialize()? "__PHP_Incomplete_Class" means PHP couldn't load the class named. Which is SiteNavigation. Are you sure the autoloader is set up properly and gets installed before the call to unserialize()? Yep this ultimately was the problem. A sub class (not SiteNavigation) was not properly getting instantiated due to a typo in an extended data class... VERY FRUSTRATING trying to track down bugs when they are three objects deep. What bubbles up isn't typically the correct problem. I was getting a path errors. Eventually (after a lot of trial and error) I created a test script to load each class individually. It was through that test script the typo was revealed... Thanks again. Edited September 27, 2015 by rwhite35 Quote Link to comment https://forums.phpfreaks.com/topic/298312-serializable-class-with-sub-classes/#findComment-1521619 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.