I have added the callbacks to class_entry structure and patches to 
serialization mechanism to allow custom object 
serialization/unserialization inside the PHP serialize mechanism.

Purpose:
--------
                                                                                
                            
Define possibility for custom serialization and userialization of PHP5
objects, which would allow users to run custom code when objects are
serialized and unserialized.
                                                                                
                            
Implementation:
---------------
                                                                                
                            
Define 2 callbacks for zend_class_entry, as follows:
                                                                                
                            
int (*serialize)(zval *object, unsigned char **buffer, zend_uint *buf_len, 
zend_serialize_data *data TSRMLS_DC);

Serializes object data into the buffer. Should serialize only object
"internals", not class name.
zend_serialize_data is the variables hash that var.c uses to track 
references. If you want to use it, consult var.c and use it the same way. 
                                                                                
                            
int (*unserialize)(zval **object, const unsigned char *buf, 
zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);

creates new zval according to the serialized data in buf, 
buf_len limits data length. Returns SUCCESS if object
created correctly, FAILURE if it failed. Data include only the object 
data, not class name, etc.

zend_unserialize_data is the variables hash that var_unserialize.re uses 
to track references. If you want to use it, consult var.c and use it the 
same way.

By default, these callbacks are NULL, meaning the standard mechanism is 
used.

Format
------

New serialization is using letter 'C' to designate custom serialization 
data. 

Example
-------

Attached in the example patch for SimpleXML that demonstrates the concept 
by using callbacks to serialize SimpleXML object's data as XML and then 
restoring it to the object back. This should allow, for example, to 
seamlessly put SimpleXML object to a session data.



-- 
Stanislav Malyshev, Zend Products Engineer   
[EMAIL PROTECTED]  http://www.zend.com/ +972-3-6139665 ext.115
Index: simplexml.c
===================================================================
RCS file: /repository/php-src/ext/simplexml/simplexml.c,v
retrieving revision 1.147
diff -u -b -r1.147 simplexml.c
--- simplexml.c 5 Dec 2004 12:02:35 -0000       1.147
+++ simplexml.c 22 Feb 2005 13:27:59 -0000
@@ -1681,6 +1681,71 @@
        {NULL, NULL, NULL}
 };
 
+int simplexml_serialize(zval *object, unsigned char **buffer, zend_uint 
*buf_len, zend_serialize_data *data TSRMLS_DC)
+{
+       php_sxe_object     *sxe;
+       xmlNodePtr          node;
+       xmlOutputBufferPtr  outbuf;
+       xmlChar            *strval;
+       int                 strval_len;
+
+       sxe = php_sxe_fetch_object(object TSRMLS_CC);
+       GET_NODE(sxe, node);
+       node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
+
+       if (node) {
+               if (XML_DOCUMENT_NODE == node->parent->type) {
+                       xmlDocDumpMemory((xmlDocPtr) sxe->document->ptr, 
&strval, &strval_len);
+               } else {
+                       /* Should we be passing encoding information instead of 
NULL? */
+                       outbuf = xmlAllocOutputBuffer(NULL);
+
+                       if (outbuf == NULL) {
+                               return FAILURE;
+                       }
+
+                       xmlNodeDumpOutput(outbuf, (xmlDocPtr) 
sxe->document->ptr, node, 0, 1, ((xmlDocPtr) sxe->document->ptr)->encoding);
+                       xmlOutputBufferFlush(outbuf);
+                       strval = xmlStrndup(outbuf->buffer->content, 
outbuf->buffer->use);
+                       xmlOutputBufferClose(outbuf);
+               }
+
+               *buffer = estrdup(strval);
+               *buf_len = strlen(*buffer);
+               xmlFree(strval);
+       } else {
+               return FAILURE;
+       }
+
+       return SUCCESS;
+}
+
+int simplexml_unserialize(zval **object, const unsigned char *buf, zend_uint 
buf_len, zend_unserialize_data *unserialize_data TSRMLS_DC)
+{
+       php_sxe_object *sxe;
+       xmlDocPtr       docp;
+       zend_class_entry *ce= sxe_class_entry;
+
+#if LIBXML_VERSION >= 20600
+       docp = xmlReadMemory(buf, buf_len, NULL, NULL, 0);
+#else
+       docp = xmlParseMemory(buf, buf_len);
+#endif
+
+       if (! docp) {
+               return FAILURE;
+       }
+
+       sxe = php_sxe_object_new(ce TSRMLS_CC);
+       php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp 
TSRMLS_CC);
+       php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, 
xmlDocGetRootElement(docp), NULL TSRMLS_CC);
+
+       MAKE_STD_ZVAL(*object);
+       Z_TYPE_PP(object) = IS_OBJECT;
+       (*object)->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
+       return SUCCESS;
+}
+
 /* {{{ PHP_MINIT_FUNCTION(simplexml)
  */
 PHP_MINIT_FUNCTION(simplexml)
@@ -1691,6 +1756,8 @@
        sxe.create_object = sxe_object_new;
        sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC);
        sxe_class_entry->get_iterator = php_sxe_get_iterator;
+       sxe_class_entry->serialize = simplexml_serialize;
+       sxe_class_entry->unserialize = simplexml_unserialize;
        zend_class_implements(sxe_class_entry TSRMLS_CC, 1, 
zend_ce_traversable);
        sxe_object_handlers.get_method = 
zend_get_std_object_handlers()->get_method;
        sxe_object_handlers.get_constructor = 
zend_get_std_object_handlers()->get_constructor;
-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to