]> granicus.if.org Git - php/commitdiff
- Support members in SplObjectStorage serialization / shorter serialization
authorMarcus Boerger <helly@php.net>
Mon, 18 Dec 2006 22:32:10 +0000 (22:32 +0000)
committerMarcus Boerger <helly@php.net>
Mon, 18 Dec 2006 22:32:10 +0000 (22:32 +0000)
ext/spl/spl_observer.c
ext/spl/tests/observer_003.phpt
ext/spl/tests/observer_004.phpt [new file with mode: 0755]

index ad02d69e82d21a9dfa20362409e8630f5076282d..49263bade5c7ab229f8229cb98be1678c0d5683f 100755 (executable)
@@ -272,46 +272,51 @@ SPL_METHOD(SplObjectStorage, serialize)
 {
        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
 
-       zval **entry;
+       zval **entry, members, *pmembers;
        HashPosition      pos;
        php_serialize_data_t var_hash;
        smart_str buf = {0};
-       long index = 0;
 
        PHP_VAR_SERIALIZE_INIT(var_hash);
 
-       smart_str_appendl(&buf, "a:", 2);
+       /* storage */
+       smart_str_appendl(&buf, "x:i:", 4);
        smart_str_append_long(&buf, zend_hash_num_elements(&intern->storage));
-       smart_str_appendl(&buf, ":{", 2);
+       smart_str_appendc(&buf, ';');
 
        zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
 
        while(zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) {
-               smart_str_appendl(&buf, "i:", 2);
-               smart_str_append_long(&buf, index++);
-               smart_str_appendc(&buf, ';');
                if (zend_hash_get_current_data_ex(&intern->storage, (void**)&entry, &pos) == FAILURE) {
                        smart_str_free(&buf);
                        PHP_VAR_SERIALIZE_DESTROY(var_hash);
-                       RETURN_FALSE;
+                       RETURN_NULL();
                }
                php_var_serialize(&buf, entry, &var_hash TSRMLS_CC);
+               smart_str_appendc(&buf, ';');
                zend_hash_move_forward_ex(&intern->storage, &pos);
        }
 
-       smart_str_appendc(&buf, '}');
-       smart_str_0(&buf);
+       /* members */
+       smart_str_appendl(&buf, "m:", 2);
+       INIT_PZVAL(&members);
+       Z_ARRVAL(members) = intern->std.properties;
+       Z_TYPE(members) = IS_ARRAY;
+       pmembers = &members;
+       php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
+
+       /* done */
        PHP_VAR_SERIALIZE_DESTROY(var_hash);
 
        if (buf.c) {
-               RETURN_ASCII_STRINGL(buf.c, buf.len, 0);
+               RETURN_ASCII_STRINGL(buf.c, buf.len, ZSTR_AUTOFREE);
        } else {
                RETURN_NULL();
        }
        
 } /* }}} */
 
-/* {{{ proto void SplObjectStorage::unserialize(string unserialized)
+/* {{{ proto void SplObjectStorage::unserialize(string serialized)
  */
 SPL_METHOD(SplObjectStorage, unserialize)
 {
@@ -319,12 +324,10 @@ SPL_METHOD(SplObjectStorage, unserialize)
 
        char *buf;
        int buf_len;
-       const unsigned char *p;
+       const unsigned char *p, *s;
        php_unserialize_data_t var_hash;
-       zval *zentries, **entry;
-       HashPosition pos;
-       
-       ALLOC_INIT_ZVAL(zentries);
+       zval *pentry, *pmembers, *pcount = NULL;
+       long count;
        
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
                return;
@@ -335,36 +338,70 @@ SPL_METHOD(SplObjectStorage, unserialize)
                return;
        }
 
-       p = (const unsigned char*)buf;
+       /* storage */
+       s = p = (const unsigned char*)buf;
        PHP_VAR_UNSERIALIZE_INIT(var_hash);
-       if (!php_var_unserialize(&zentries, &p, p + buf_len,  &var_hash TSRMLS_CC)) {
-               PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
-               zval_ptr_dtor(&zentries);
-               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
-               return;
-       }
-       PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
 
-       /* move from temp array to storage */
-       
-       if (Z_TYPE_P(zentries) != IS_ARRAY) {
-               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Serialize string must contain a single array");
-               return;
+       if (*p!= 'x' || *++p != ':') {
+               goto outexcept;
        }
+       ++p;
 
-       zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zentries), &pos);
+       ALLOC_INIT_ZVAL(pcount);
+       if (!php_var_unserialize(&pcount, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
+               zval_ptr_dtor(&pcount);
+               goto outexcept;
+       }
 
-       while(zend_hash_has_more_elements_ex(Z_ARRVAL_P(zentries), &pos) == SUCCESS) {
-               if (zend_hash_get_current_data_ex(Z_ARRVAL_P(zentries), (void**)&entry, &pos) == FAILURE || Z_TYPE_PP(entry) != IS_OBJECT) {
-                       zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Serialize string must only contain objects");            
-                       zval_ptr_dtor(&zentries);
-                       return;
+       --p; /* for ';' */
+       count = Z_LVAL_P(pcount);
+       zval_ptr_dtor(&pcount);
+               
+       while(count-- > 0) {
+               if (*p != ';') {
+                       goto outexcept;
+               }
+               ++p;
+               ALLOC_INIT_ZVAL(pentry);
+               if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) {
+                       zval_ptr_dtor(&pentry);
+                       goto outexcept;
                }
-               spl_object_storage_attach(intern, *entry TSRMLS_CC);
-               zend_hash_move_forward_ex(Z_ARRVAL_P(zentries), &pos);
+               spl_object_storage_attach(intern, pentry TSRMLS_CC);
+               zval_ptr_dtor(&pentry);
        }
-       
-       zval_ptr_dtor(&zentries);
+
+       if (*p != ';') {
+               goto outexcept;
+       }
+       ++p;
+
+       /* members */
+       if (*p!= 'm' || *++p != ':') {
+               goto outexcept;
+       }
+       ++p;
+
+       ALLOC_INIT_ZVAL(pmembers);
+       if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
+               zval_ptr_dtor(&pmembers);
+               goto outexcept;
+       }
+
+       /* copy members */
+       zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
+       zval_ptr_dtor(&pmembers);
+
+       /* done reading $serialized */
+
+       PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+       return;
+
+outexcept:
+       PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+       zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+       return;
+
 } /* }}} */
 
 static
index 6d3ed9d3fff1fa65b04be4678e9168aad992499e..c9329c4c40506fb0ef58cdb55a8a9877dfe15b50 100755 (executable)
@@ -29,6 +29,7 @@ foreach($storage as $object)
        var_dump($object->test);
 }
 
+var_dump(serialize($storage));
 echo "===UNSERIALIZE===\n";
 
 $storage2 = unserialize(serialize($storage));
@@ -43,12 +44,13 @@ foreach($storage2 as $object)
 ?>
 ===DONE===
 <?php exit(0); ?>
---EXPECT--
+--EXPECTF--
 int(4)
 int(1)
 string(1) "2"
 string(3) "foo"
 bool(true)
+string(%d) "%s"
 ===UNSERIALIZE===
 int(4)
 int(1)
@@ -56,12 +58,13 @@ string(1) "2"
 string(3) "foo"
 bool(true)
 ===DONE===
---UEXPECT--
+--UEXPECTF--
 int(4)
 int(1)
 unicode(1) "2"
 unicode(3) "foo"
 bool(true)
+unicode(%d) "%s"
 ===UNSERIALIZE===
 int(4)
 int(1)
diff --git a/ext/spl/tests/observer_004.phpt b/ext/spl/tests/observer_004.phpt
new file mode 100755 (executable)
index 0000000..5d1814f
--- /dev/null
@@ -0,0 +1,96 @@
+--TEST--
+SPL: SplObjectStorage overloaded & serialization
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class TestClass
+{
+       public $test = 25;
+       
+       public function __construct($test = 42)
+       {
+               $this->test = $test;
+       }
+}
+
+class MyStorage extends SplObjectStorage
+{
+       public $bla = 25;
+       
+       public function __construct($bla = 26)
+       {
+               $this->bla = $bla;
+       }
+}
+
+$storage = new MyStorage();
+
+foreach(array(1,2) as $value)
+{
+     $storage->attach(new TestClass($value));
+}
+
+var_dump(count($storage));
+
+foreach($storage as $object)
+{
+       var_dump($object->test);
+}
+
+var_dump($storage);
+
+var_dump(serialize($storage));
+echo "===UNSERIALIZE===\n";
+
+$storage2 = unserialize(serialize($storage));
+
+var_dump(count($storage2));
+
+foreach($storage2 as $object)
+{
+       var_dump($object->test);
+}
+
+var_dump($storage2);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(2)
+int(1)
+int(2)
+object(MyStorage)#%d (1) {
+  ["bla"]=>
+  int(26)
+}
+string(%d) "%s"
+===UNSERIALIZE===
+int(2)
+int(1)
+int(2)
+object(MyStorage)#%d (1) {
+  ["bla"]=>
+  int(26)
+}
+===DONE===
+--UEXPECTF--
+int(2)
+int(1)
+int(2)
+object(MyStorage)#%d (1) {
+  [u"bla"]=>
+  int(26)
+}
+unicode(%d) "%s"
+===UNSERIALIZE===
+int(2)
+int(1)
+int(2)
+object(MyStorage)#%d (1) {
+  [u"bla"]=>
+  int(26)
+}
+===DONE===