Re: [PHP4BETA] serialize() musings...

From: Date: Mon, 12 Apr 1999 08:12:29 +0000
Subject: Re: [PHP4BETA] serialize() musings...
References: 1  Groups: php.version4 
Request: Send a blank email to php-version4+get-81@lists.php.net to get a copy of this message
Zeev Suraski schrieb: > That said, I think you have a fundemental mistake in > your entire approach to serialzation. Objects *never* > serialize their methods. In PHP4, objects don't even > really have methods, they belong to a class. When you > want to serialize an object, you serialize its stateful > data only, not its methods. We both agree on this. I do not serialize an objects methods, but only the stateful data of an object. I ask that you see for yourself by following me through the example below, because it makes further discussion much easier. Please have a look at the actual saved state of a session, because I will use it as an example. kk@poe ~ $ ./sesdump.pl name=M_Session sid=488f19acdf4867a623c947ed10a09353 changed=19990322111358 val = '$this->in = ""; $this->pt = array(); $this->pt["lang"] = "1"; $this->pt["beenthere"] = "1"; $this->pt["cart"] = "1"; $GLOBALS["lang"] = "en"; $GLOBALS["beenthere"] = array(); $GLOBALS["beenthere"]["VLB"] = "yes"; $GLOBALS["beenthere"]["KNO"] = "yes"; $GLOBALS["beenthere"]["VLZ"] = "yes"; $GLOBALS["cart"] = new M_Cart; $GLOBALS["cart"]->item = array(); $GLOBALS["cart"]->item["1"] = array(); $GLOBALS["cart"]->item["1"]["art"] = "163-1468"; $GLOBALS["cart"]->item["1"]["num"] = "1"; $GLOBALS["cart"]->currentItem = "2"; This is a dump of a session named "M_Session" with a Session id of "488...353". It has been updated at 22-Mar-1999 for the last time (this is a development server which does not expire old sessions). The val-string is the actual saved state of the session and it is saved in the form of an executeable PHP program. This is only because I am a lazy programmer and did not want to write a parser for my session state when I already have a perfectly working parser at hand (PHP's eval() statement). The session contains a saved scalar $lang, a saved array $beenthere[] and a saved object $cart of the class M_Cart. The saved object is complex: It contains a multidimensional array that is saved with it. I chose the example, because it contains most of the cases you can encounter besides references (which weren't available until now). The session state saves the following things ($this in the context of the session state means the session object itself. $this-variables in a saved session refer to internal variable of the session): - $this->in A flag which indicates if the session has one-shot startup code to execute and if that code already has run. If a session has startup code, we include() that code, run it and set $this->in to "1" so that we remember that we are already initialized and do not run that code again. - $this->pt[] A hash that contains the names of all global symbols that are to be serialized. If you register a variable with the session management, its name is stored in $this->[] and it is serialized and written away each time a page closes. We also serialize $this->pt[], to that the registered names are persistent themselves. - $GLOBALS[] This are the actual saved variables. Note that we take care to reconstruct the proper type for each variable. We generate $GLOBALS["beenthere"] = array(); even for an empty array $beenthere[], because otherwise we get problems with restoring such cases. That's all that is saved in one of PHPLIBs sessions. So much for the general background, now to your comments: We do serialize object stateful data, but no methods, just like you said we should. Saving methods would be quite pointless, because we already have the objects methods in a serialized form that can be easily loaded: That is the include file in which the class was defined in the first place (we have the convention of defining each class and only that class in a seperate include file, but we do not depend on that convention - see below). We do not serialize all stateful data in an object in some cases, because that would be not only pointless, but dangerous as well. An example is the session object itself, as shown in the example above: The session object has many variables, many of which are constants. These are being set by PHPLIB users to configure the library. There is no point in saving these, because the values never change. Also, the session object contains a database connection object, which in turn contains a variable $Link_ID, which is the result of a mysql_pconnect() call. We must not save that value, because it is only a handle for an opaque data structure outside the scope of PHP (the socket to the database server) and that structure cannot be serialized - since the connection is lost at the end of the page, the $Link_ID must be lost, too, so that we can discover that we have no database link, yet, and must recreate it. Thus the need for NOT serialzing certain state in some cases. As for serializing objects: The current implementation of the serialize() builtin in PHP3 does save all object state, but it does not retain the class-object connection. An unserialized() object is of no class at all - I cannot invoke any methods on such an object. A proper implementation of serialize() and unserialize() in PHP4 or Zend must retain the class of an object, i.e. it must do the semantic equivalent of the "$GLOBALS["cart"] = new M_Cart;" statement in the example above. As of now, the serialize()/unserialize() implementation in PHP3 is useless for PHPLIB because (in order of severity): - unserialized() objects do not retain their class - serialize() always saves the complete object state That is why PHPLIB comes with an independent serialize() method instead of using the PHP3 builtin. A final note on "serializing methods of classes": Currently, PHPLIB requires that you always include all class definitions of objects that might be serialized at any time by your application. PHPLIB needs to be able to execute statements like '$GLOBALS["cart"] = new M_Cart;' when the need arises. There is no way to include only the needed files (i.e. to NOT include 'cart.inc' unless there is a $cart object within the current session state), because the unserializing function (Session::thaw() in PHPLIB) is just that: a function. You cannot define a global class (by executing 'include("cart.inc")') from within a function context currently. This is not a problem, but it would be a nice optimization for PHPLIB. PHPLIB would then optionally generate an appropriate include() statement in the session state for each saved object. A final note on the format of the saved session: Currently, we generate arrays and object by executing a string of statements creating the individual slots of the arrays and objects one at a time. We experimented with a syntax like $GLOBALS["beenthere"] = array( "VLB" => "yes, "KNO" => "yes", "VLZ" => "yes" ); but decided against it, because PHP3 does have a syntax for array constants, but no syntax for object constants, i.e. there is no construct like $GLOBALS["cart"] = object("M_Cart", array( 1 => array( "art" => "163-1468", "num" => "1" ) ), currentItem = 2 ); This is a kind of asymmetry in the language: We have constant notations for all scalar types and for arrays, but not for objects. Again, this only an observation: The syntax we currently use is in fact easier to generate and maintain that the nested syntax above. Kristian -- Kristian Köhntopp, NetUSE Kommunikationstechnologie GmbH Siemenswall, D-24107 Kiel, Germany, +49 431 386 436 00 Using PHP3? See our web development library at http://phplib.shonline.de/ (GPL) -- PHP 4 Beta

« previous php.version4 (#81) next »