Selaa lähdekoodia

Add clear method to PHP message (#2700)

Paul Yang 8 vuotta sitten
vanhempi
commit
74eb9a0a30

+ 19 - 0
php/ext/google/protobuf/message.c

@@ -38,6 +38,7 @@ static zend_class_entry* message_type;
 zend_object_handlers* message_handlers;
 
 static  zend_function_entry message_methods[] = {
+  PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC)
   PHP_ME(Message, encode, NULL, ZEND_ACC_PUBLIC)
   PHP_ME(Message, decode, NULL, ZEND_ACC_PUBLIC)
   PHP_ME(Message, jsonEncode, NULL, ZEND_ACC_PUBLIC)
@@ -241,6 +242,24 @@ PHP_METHOD(Message, __construct) {
   }
 }
 
+PHP_METHOD(Message, clear) {
+  MessageHeader* msg =
+      (MessageHeader*)zend_object_store_get_object(getThis() TSRMLS_CC);
+  Descriptor* desc = msg->descriptor;
+  zend_class_entry* ce = desc->klass;
+  int i;
+
+  for (i = 0; i < msg->std.ce->default_properties_count; i++) {
+    zval_ptr_dtor(&msg->std.properties_table[i]);
+  }
+  efree(msg->std.properties_table);
+
+  zend_object_std_init(&msg->std, ce TSRMLS_CC);
+  object_properties_init(&msg->std, ce);
+  layout_init(desc->layout, message_data(msg),
+              msg->std.properties_table TSRMLS_CC);
+}
+
 PHP_METHOD(Message, readOneof) {
   long index;
 

+ 1 - 0
php/ext/google/protobuf/protobuf.h

@@ -244,6 +244,7 @@ const char* layout_get_oneof_case(MessageLayout* layout, const void* storage,
                                   const upb_oneofdef* oneof TSRMLS_DC);
 void free_layout(MessageLayout* layout);
 
+PHP_METHOD(Message, clear);
 PHP_METHOD(Message, readOneof);
 PHP_METHOD(Message, writeOneof);
 PHP_METHOD(Message, whichOneof);

+ 19 - 2
php/ext/google/protobuf/storage.c

@@ -248,11 +248,28 @@ void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC) {
     CASE(DOUBLE, DOUBLE)
     CASE(BOOL, BOOL)
     CASE(INT32, LONG)
-    CASE(INT64, LONG)
     CASE(UINT32, LONG)
-    CASE(UINT64, LONG)
     CASE(ENUM, LONG)
 
+#undef CASE
+
+#if SIZEOF_LONG == 4
+#define CASE(upb_type)                                \
+    case UPB_TYPE_##upb_type: {                       \
+      SEPARATE_ZVAL_IF_NOT_REF(cache);                \
+      ZVAL_STRING(*cache, "0", 1);                    \
+      return;                                         \
+    }
+#else
+#define CASE(upb_type)                                \
+    case UPB_TYPE_##upb_type: {                       \
+      SEPARATE_ZVAL_IF_NOT_REF(cache);                \
+      ZVAL_LONG(*cache, 0);                           \
+      return;                                         \
+    }
+#endif
+CASE(UINT64)
+CASE(INT64)
 #undef CASE
 
     case UPB_TYPE_STRING:

+ 110 - 1
php/src/Google/Protobuf/Internal/Message.php

@@ -125,7 +125,7 @@ class Message
                 $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
                 $oneof_name = $oneof->getName();
                 $this->$oneof_name = new OneofField($oneof);
-            } else if ($field->getLabel() === GPBLabel::OPTIONAL && 
+            } else if ($field->getLabel() === GPBLabel::OPTIONAL &&
                        PHP_INT_SIZE == 4) {
                 switch ($field->getType()) {
                     case GPBType::INT64:
@@ -381,6 +381,115 @@ class Message
         return true;
     }
 
+    /**
+     * Clear all containing fields.
+     * @return null.
+     */
+    public function clear()
+    {
+        foreach ($this->desc->getField() as $field) {
+            $setter = $field->getSetter();
+            if ($field->isMap()) {
+                $message_type = $field->getMessageType();
+                $key_field = $message_type->getFieldByNumber(1);
+                $value_field = $message_type->getFieldByNumber(2);
+                switch ($value_field->getType()) {
+                    case GPBType::MESSAGE:
+                    case GPBType::GROUP:
+                        $map_field = new MapField(
+                            $key_field->getType(),
+                            $value_field->getType(),
+                            $value_field->getMessageType()->getClass());
+                        $this->$setter($map_field);
+                        break;
+                    case GPBType::ENUM:
+                        $map_field = new MapField(
+                            $key_field->getType(),
+                            $value_field->getType(),
+                            $value_field->getEnumType()->getClass());
+                        $this->$setter($map_field);
+                        break;
+                    default:
+                        $map_field = new MapField(
+                            $key_field->getType(),
+                            $value_field->getType());
+                        $this->$setter($map_field);
+                        break;
+                }
+            } else if ($field->getLabel() === GPBLabel::REPEATED) {
+                switch ($field->getType()) {
+                    case GPBType::MESSAGE:
+                    case GPBType::GROUP:
+                        $repeated_field = new RepeatedField(
+                            $field->getType(),
+                            $field->getMessageType()->getClass());
+                        $this->$setter($repeated_field);
+                        break;
+                    case GPBType::ENUM:
+                        $repeated_field = new RepeatedField(
+                            $field->getType(),
+                            $field->getEnumType()->getClass());
+                        $this->$setter($repeated_field);
+                        break;
+                    default:
+                        $repeated_field = new RepeatedField($field->getType());
+                        $this->$setter($repeated_field);
+                        break;
+                }
+            } else if ($field->getOneofIndex() !== -1) {
+                $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
+                $oneof_name = $oneof->getName();
+                $this->$oneof_name = new OneofField($oneof);
+            } else if ($field->getLabel() === GPBLabel::OPTIONAL) {
+                switch ($field->getType()) {
+                    case GPBType::DOUBLE   :
+                    case GPBType::FLOAT    :
+                        $this->$setter(0.0);
+                        break;
+                    case GPBType::INT32    :
+                    case GPBType::FIXED32  :
+                    case GPBType::UINT32   :
+                    case GPBType::SFIXED32 :
+                    case GPBType::SINT32   :
+                    case GPBType::ENUM     :
+                        $this->$setter(0);
+                        break;
+                    case GPBType::BOOL     :
+                        $this->$setter(false);
+                        break;
+                    case GPBType::STRING   :
+                    case GPBType::BYTES    :
+                        $this->$setter("");
+                        break;
+                    case GPBType::GROUP    :
+                    case GPBType::MESSAGE  :
+                        $null = null;
+                        $this->$setter($null);
+                        break;
+                }
+                if (PHP_INT_SIZE == 4) {
+                    switch ($field->getType()) {
+                        case GPBType::INT64:
+                        case GPBType::UINT64:
+                        case GPBType::FIXED64:
+                        case GPBType::SFIXED64:
+                        case GPBType::SINT64:
+                            $this->$setter("0");
+                    }
+                } else {
+                    switch ($field->getType()) {
+                        case GPBType::INT64:
+                        case GPBType::UINT64:
+                        case GPBType::FIXED64:
+                        case GPBType::SFIXED64:
+                        case GPBType::SINT64:
+                            $this->$setter(0);
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Parses a protocol buffer contained in a string.
      *

+ 2 - 1
php/tests/encode_decode_test.php

@@ -22,7 +22,8 @@ class EncodeDecodeTest extends TestBase
         $this->expectFields($from);
 
         $data = $from->encode();
-        $this->assertSame(TestUtil::getGoldenTestMessage(), $data);
+        $this->assertSame(bin2hex(TestUtil::getGoldenTestMessage()),
+                          bin2hex($data));
     }
 
     public function testDecode()

+ 21 - 5
php/tests/generated_class_test.php

@@ -2,6 +2,7 @@
 
 require_once('generated/NoNameSpaceEnum.php');
 require_once('generated/NoNameSpaceMessage.php');
+require_once('test_base.php');
 require_once('test_util.php');
 
 use Google\Protobuf\Internal\RepeatedField;
@@ -10,7 +11,7 @@ use Foo\TestEnum;
 use Foo\TestMessage;
 use Foo\TestMessage_Sub;
 
-class GeneratedClassTest extends PHPUnit_Framework_TestCase
+class GeneratedClassTest extends TestBase
 {
 
     #########################################################
@@ -607,15 +608,30 @@ class GeneratedClassTest extends PHPUnit_Framework_TestCase
         $this->assertSame("oneof_message", $m->getMyOneof());
     }
 
+    #########################################################
+    # Test clear method.
+    #########################################################
+
+    public function testMessageClear()
+    {
+        $m = new TestMessage();
+        $this->setFields($m);
+        $this->expectFields($m);
+        $m->clear();
+        $this->expectEmptyFields($m);
+    }
+
     #########################################################
     # Test message/enum without namespace.
     #########################################################
 
-    public function testMessageWithoutNamespace() {
-      $m = new NoNameSpaceMessage();
+    public function testMessageWithoutNamespace()
+    {
+        $m = new NoNameSpaceMessage();
     }
 
-    public function testEnumWithoutNamespace() {
-      $m = new NoNameSpaceEnum();
+    public function testEnumWithoutNamespace()
+    {
+        $m = new NoNameSpaceEnum();
     }
 }

+ 1 - 1
php/tests/php_implementation_test.php

@@ -496,7 +496,7 @@ class ImplementationTest extends TestBase
     {
         $m = new TestMessage();
         TestUtil::setTestMessage($m);
-        $this->assertSame(447, $m->byteSize());
+        $this->assertSame(481, $m->byteSize());
     }
 
     public function testPackedByteSize()

+ 95 - 0
php/tests/test_base.php

@@ -1,6 +1,7 @@
 <?php
 
 use Foo\TestMessage;
+use Foo\TestEnum;
 use Foo\TestMessage_Sub;
 
 class TestBase extends PHPUnit_Framework_TestCase
@@ -69,6 +70,32 @@ class TestBase extends PHPUnit_Framework_TestCase
         $this->assertEquals('c',   $m->getRepeatedString()[1]);
         $this->assertEquals('d',   $m->getRepeatedBytes()[1]);
         $this->assertEquals(35,    $m->getRepeatedMessage()[1]->GetA());
+
+        if (PHP_INT_SIZE == 4) {
+            $this->assertEquals('-63', $m->getMapInt64Int64()['-63']);
+            $this->assertEquals('63',  $m->getMapUint64Uint64()['63']);
+            $this->assertEquals('-65', $m->getMapSint64Sint64()['-65']);
+            $this->assertEquals('67',  $m->getMapFixed64Fixed64()['67']);
+            $this->assertEquals('-69',  $m->getMapSfixed64Sfixed64()['-69']);
+        } else {
+            $this->assertEquals(-63, $m->getMapInt64Int64()[-63]);
+            $this->assertEquals(63,  $m->getMapUint64Uint64()[63]);
+            $this->assertEquals(-65, $m->getMapSint64Sint64()[-65]);
+            $this->assertEquals(67,  $m->getMapFixed64Fixed64()[67]);
+            $this->assertEquals(-69,  $m->getMapSfixed64Sfixed64()[-69]);
+        }
+        $this->assertEquals(-62, $m->getMapInt32Int32()[-62]);
+        $this->assertEquals(62,  $m->getMapUint32Uint32()[62]);
+        $this->assertEquals(-64, $m->getMapSint32Sint32()[-64]);
+        $this->assertEquals(66,  $m->getMapFixed32Fixed32()[66]);
+        $this->assertEquals(-68,  $m->getMapSfixed32Sfixed32()[-68]);
+        $this->assertEquals(3.5, $m->getMapInt32Float()[1]);
+        $this->assertEquals(3.6, $m->getMapInt32Double()[1]);
+        $this->assertEquals(true , $m->getMapBoolBool()[true]);
+        $this->assertEquals('e', $m->getMapStringString()['e']);
+        $this->assertEquals('f', $m->getMapInt32Bytes()[1]);
+        $this->assertEquals(TestEnum::ONE, $m->getMapInt32Enum()[1]);
+        $this->assertEquals(36, $m->getMapInt32Message()[1]->GetA());
     }
 
     public function expectEmptyFields(TestMessage $m)
@@ -83,7 +110,10 @@ class TestBase extends PHPUnit_Framework_TestCase
         $this->assertSame(false, $m->getOptionalBool());
         $this->assertSame('',  $m->getOptionalString());
         $this->assertSame('',  $m->getOptionalBytes());
+        $this->assertSame(0, $m->getOptionalEnum());
         $this->assertNull($m->getOptionalMessage());
+        $this->assertNull($m->getOptionalIncludedMessage());
+        $this->assertNull($m->getRecursive());
         if (PHP_INT_SIZE == 4) {
             $this->assertSame("0", $m->getOptionalInt64());
             $this->assertSame("0", $m->getOptionalUint64());
@@ -97,6 +127,71 @@ class TestBase extends PHPUnit_Framework_TestCase
             $this->assertSame(0, $m->getOptionalFixed64());
             $this->assertSame(0, $m->getOptionalSfixed64());
         }
+
+        $this->assertEquals(0, count($m->getRepeatedInt32()));
+        $this->assertEquals(0, count($m->getRepeatedUint32()));
+        $this->assertEquals(0, count($m->getRepeatedInt64()));
+        $this->assertEquals(0, count($m->getRepeatedUint64()));
+        $this->assertEquals(0, count($m->getRepeatedSint32()));
+        $this->assertEquals(0, count($m->getRepeatedSint64()));
+        $this->assertEquals(0, count($m->getRepeatedFixed32()));
+        $this->assertEquals(0, count($m->getRepeatedFixed64()));
+        $this->assertEquals(0, count($m->getRepeatedSfixed32()));
+        $this->assertEquals(0, count($m->getRepeatedSfixed64()));
+        $this->assertEquals(0, count($m->getRepeatedFloat()));
+        $this->assertEquals(0, count($m->getRepeatedDouble()));
+        $this->assertEquals(0, count($m->getRepeatedBool()));
+        $this->assertEquals(0, count($m->getRepeatedString()));
+        $this->assertEquals(0, count($m->getRepeatedBytes()));
+        $this->assertEquals(0, count($m->getRepeatedEnum()));
+        $this->assertEquals(0, count($m->getRepeatedMessage()));
+        $this->assertEquals(0, count($m->getRepeatedRecursive()));
+
+        $this->assertSame("", $m->getMyOneof());
+        $this->assertSame(0,   $m->getOneofInt32());
+        $this->assertSame(0,   $m->getOneofUint32());
+        $this->assertSame(0,   $m->getOneofSint32());
+        $this->assertSame(0,   $m->getOneofFixed32());
+        $this->assertSame(0,   $m->getOneofSfixed32());
+        $this->assertSame(0.0, $m->getOneofFloat());
+        $this->assertSame(0.0, $m->getOneofDouble());
+        $this->assertSame(false, $m->getOneofBool());
+        $this->assertSame('',  $m->getOneofString());
+        $this->assertSame('',  $m->getOneofBytes());
+        $this->assertSame(0, $m->getOneofEnum());
+        $this->assertNull($m->getOptionalMessage());
+        if (PHP_INT_SIZE == 4) {
+            $this->assertSame("0", $m->getOneofInt64());
+            $this->assertSame("0", $m->getOneofUint64());
+            $this->assertSame("0", $m->getOneofSint64());
+            $this->assertSame("0", $m->getOneofFixed64());
+            $this->assertSame("0", $m->getOneofSfixed64());
+        } else {
+            $this->assertSame(0, $m->getOneofInt64());
+            $this->assertSame(0, $m->getOneofUint64());
+            $this->assertSame(0, $m->getOneofSint64());
+            $this->assertSame(0, $m->getOneofFixed64());
+            $this->assertSame(0, $m->getOneofSfixed64());
+        }
+
+        $this->assertEquals(0, count($m->getMapInt64Int64()));
+        $this->assertEquals(0, count($m->getMapUint64Uint64()));
+        $this->assertEquals(0, count($m->getMapSint64Sint64()));
+        $this->assertEquals(0, count($m->getMapFixed64Fixed64()));
+        $this->assertEquals(0, count($m->getMapInt32Int32()));
+        $this->assertEquals(0, count($m->getMapUint32Uint32()));
+        $this->assertEquals(0, count($m->getMapSint32Sint32()));
+        $this->assertEquals(0, count($m->getMapFixed32Fixed32()));
+        $this->assertEquals(0, count($m->getMapSfixed32Sfixed32()));
+        $this->assertEquals(0, count($m->getMapSfixed64Sfixed64()));
+        $this->assertEquals(0, count($m->getMapInt32Float()));
+        $this->assertEquals(0, count($m->getMapInt32Double()));
+        $this->assertEquals(0, count($m->getMapBoolBool()));
+        $this->assertEquals(0, count($m->getMapStringString()));
+        $this->assertEquals(0, count($m->getMapInt32Bytes()));
+        $this->assertEquals(0, count($m->getMapInt32Enum()));
+        $this->assertEquals(0, count($m->getMapInt32Message()));
+        $this->assertEquals(0, count($m->getMapRecursive()));
     }
 
   // This test is to avoid the warning of no test by php unit.

+ 7 - 0
php/tests/test_util.php

@@ -118,6 +118,8 @@ class TestUtil
         $m->getMapSint64Sint64()[-65] = -65;
         $m->getMapFixed32Fixed32()[66] = 66;
         $m->getMapFixed64Fixed64()[67] = 67;
+        $m->getMapSfixed32Sfixed32()[-68] = -68;
+        $m->getMapSfixed64Sfixed64()[-69] = -69;
         $m->getMapInt32Float()[1] = 3.5;
         $m->getMapInt32Double()[1] = 3.6;
         $m->getMapBoolBool()[true] = true;
@@ -213,16 +215,19 @@ class TestUtil
             assert('63'  === $m->getMapUint64Uint64()['63']);
             assert('-65' === $m->getMapSint64Sint64()['-65']);
             assert('67'  === $m->getMapFixed64Fixed64()['67']);
+            assert('-69'  === $m->getMapSfixed64Sfixed64()['-69']);
         } else {
             assert(-63 === $m->getMapInt64Int64()[-63]);
             assert(63  === $m->getMapUint64Uint64()[63]);
             assert(-65 === $m->getMapSint64Sint64()[-65]);
             assert(67  === $m->getMapFixed64Fixed64()[67]);
+            assert(-69  === $m->getMapSfixed64Sfixed64()[-69]);
         }
         assert(-62 === $m->getMapInt32Int32()[-62]);
         assert(62  === $m->getMapUint32Uint32()[62]);
         assert(-64 === $m->getMapSint32Sint32()[-64]);
         assert(66  === $m->getMapFixed32Fixed32()[66]);
+        assert(-68  === $m->getMapSfixed32Sfixed32()[-68]);
         assert(3.5 === $m->getMapInt32Float()[1]);
         assert(3.6 === $m->getMapInt32Double()[1]);
         assert(true === $m->getMapBoolBool()[true]);
@@ -296,6 +301,8 @@ class TestUtil
             "E20406088101108101" .
             "EA040A0D420000001542000000" .
             "F20412094300000000000000114300000000000000" .
+            "FA040A0DBCFFFFFF15BCFFFFFF" .
+            "82051209BBFFFFFFFFFFFFFF11BBFFFFFFFFFFFFFF" .
             "8A050708011500006040" .
             "92050B080111CDCCCCCCCCCC0C40" .
             "9A050408011001" .

+ 2 - 2
tests.sh

@@ -445,10 +445,10 @@ build_php5.5_c_32() {
   use_php_bc 5.5
   wget https://phar.phpunit.de/phpunit-old.phar -O /usr/bin/phpunit
   cd php/tests && /bin/bash ./test.sh && cd ../..
-  pushd conformance
   # TODO(teboring): Add conformance test.
+  # pushd conformance
   # make test_php_c
-  popd
+  # popd
 }
 
 build_php5.6() {