PHP: Add Enum methods for converting to/from strings (#5342)

* adds string-to-int and int-to-string methods to enums

* remove check for valueToName property in EnumTrait

* Remove unused imports

* Update to avoid using EnumTrait

* Remove EnumTrait

* Update enum types

* Move name and value methods into generated classes

* Remove functions from GPBUtil

* Test well known enums

* Implement enum value to/from name in c extension

* Only generate use statement when namespace is present
This commit is contained in:
michaelbausor 2018-11-28 16:44:53 -08:00 committed by Paul Yang
parent bfdc2ba0ee
commit 0b9af83dae
15 changed files with 633 additions and 2 deletions

View File

@ -862,6 +862,8 @@ static void init_file_wrappers(TSRMLS_D) {
// -----------------------------------------------------------------------------
static zend_function_entry field_cardinality_methods[] = {
PHP_ME(Field_Cardinality, name, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(Field_Cardinality, value, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
{NULL, NULL, NULL}
};
@ -886,11 +888,60 @@ PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field\\Cardinality",
#endif
PHP_PROTO_INIT_ENUMCLASS_END
PHP_METHOD(Field_Cardinality, name) {
PHP_PROTO_LONG value;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) ==
FAILURE) {
return;
}
switch (value) {
case 0:
PHP_PROTO_RETURN_STRING("CARDINALITY_UNKNOWN", 1);
case 1:
PHP_PROTO_RETURN_STRING("CARDINALITY_OPTIONAL", 1);
case 2:
PHP_PROTO_RETURN_STRING("CARDINALITY_REQUIRED", 1);
case 3:
PHP_PROTO_RETURN_STRING("CARDINALITY_REPEATED", 1);
default:
zend_throw_exception(
NULL,
"Enum Google\\Protobuf\\Field_Cardinality has no name "
"defined for value %d.",
value,
0 TSRMLS_CC);
}
}
PHP_METHOD(Field_Cardinality, value) {
char *name = NULL;
PHP_PROTO_SIZE name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) ==
FAILURE) {
return;
}
if (strncmp(name, "CARDINALITY_UNKNOWN", name_len) == 0) RETURN_LONG(0);
if (strncmp(name, "CARDINALITY_OPTIONAL", name_len) == 0) RETURN_LONG(1);
if (strncmp(name, "CARDINALITY_REQUIRED", name_len) == 0) RETURN_LONG(2);
if (strncmp(name, "CARDINALITY_REPEATED", name_len) == 0) RETURN_LONG(3);
zend_throw_exception(
NULL,
"Enum Google\\Protobuf\\Field_Cardinality has no value "
"defined for name %s.",
name,
0 TSRMLS_CC);
}
// -----------------------------------------------------------------------------
// Field_Kind
// -----------------------------------------------------------------------------
static zend_function_entry field_kind_methods[] = {
PHP_ME(Field_Kind, name, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(Field_Kind, value, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
{NULL, NULL, NULL}
};
@ -945,11 +996,105 @@ PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field\\Kind",
#endif
PHP_PROTO_INIT_ENUMCLASS_END
PHP_METHOD(Field_Kind, name) {
PHP_PROTO_LONG value;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) ==
FAILURE) {
return;
}
switch (value) {
case 0:
PHP_PROTO_RETURN_STRING("TYPE_UNKNOWN", 1);
case 1:
PHP_PROTO_RETURN_STRING("TYPE_DOUBLE", 1);
case 2:
PHP_PROTO_RETURN_STRING("TYPE_FLOAT", 1);
case 3:
PHP_PROTO_RETURN_STRING("TYPE_INT64", 1);
case 4:
PHP_PROTO_RETURN_STRING("TYPE_UINT64", 1);
case 5:
PHP_PROTO_RETURN_STRING("TYPE_INT32", 1);
case 6:
PHP_PROTO_RETURN_STRING("TYPE_FIXED64", 1);
case 7:
PHP_PROTO_RETURN_STRING("TYPE_FIXED32", 1);
case 8:
PHP_PROTO_RETURN_STRING("TYPE_BOOL", 1);
case 9:
PHP_PROTO_RETURN_STRING("TYPE_STRING", 1);
case 10:
PHP_PROTO_RETURN_STRING("TYPE_GROUP", 1);
case 11:
PHP_PROTO_RETURN_STRING("TYPE_MESSAGE", 1);
case 12:
PHP_PROTO_RETURN_STRING("TYPE_BYTES", 1);
case 13:
PHP_PROTO_RETURN_STRING("TYPE_UINT32", 1);
case 14:
PHP_PROTO_RETURN_STRING("TYPE_ENUM", 1);
case 15:
PHP_PROTO_RETURN_STRING("TYPE_SFIXED32", 1);
case 16:
PHP_PROTO_RETURN_STRING("TYPE_SFIXED64", 1);
case 17:
PHP_PROTO_RETURN_STRING("TYPE_SINT32", 1);
case 18:
PHP_PROTO_RETURN_STRING("TYPE_SINT64", 1);
default:
zend_throw_exception(
NULL,
"Enum Google\\Protobuf\\Field_Kind has no name "
"defined for value %d.",
value,
0 TSRMLS_CC);
}
}
PHP_METHOD(Field_Kind, value) {
char *name = NULL;
PHP_PROTO_SIZE name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) ==
FAILURE) {
return;
}
if (strncmp(name, "TYPE_UNKNOWN", name_len) == 0) RETURN_LONG(0);
if (strncmp(name, "TYPE_DOUBLE", name_len) == 0) RETURN_LONG(1);
if (strncmp(name, "TYPE_FLOAT", name_len) == 0) RETURN_LONG(2);
if (strncmp(name, "TYPE_INT64", name_len) == 0) RETURN_LONG(3);
if (strncmp(name, "TYPE_UINT64", name_len) == 0) RETURN_LONG(4);
if (strncmp(name, "TYPE_INT32", name_len) == 0) RETURN_LONG(5);
if (strncmp(name, "TYPE_FIXED64", name_len) == 0) RETURN_LONG(6);
if (strncmp(name, "TYPE_FIXED32", name_len) == 0) RETURN_LONG(7);
if (strncmp(name, "TYPE_BOOL", name_len) == 0) RETURN_LONG(8);
if (strncmp(name, "TYPE_STRING", name_len) == 0) RETURN_LONG(9);
if (strncmp(name, "TYPE_GROUP", name_len) == 0) RETURN_LONG(10);
if (strncmp(name, "TYPE_MESSAGE", name_len) == 0) RETURN_LONG(11);
if (strncmp(name, "TYPE_BYTES", name_len) == 0) RETURN_LONG(12);
if (strncmp(name, "TYPE_UINT32", name_len) == 0) RETURN_LONG(13);
if (strncmp(name, "TYPE_ENUM", name_len) == 0) RETURN_LONG(14);
if (strncmp(name, "TYPE_SFIXED32", name_len) == 0) RETURN_LONG(15);
if (strncmp(name, "TYPE_SFIXED64", name_len) == 0) RETURN_LONG(16);
if (strncmp(name, "TYPE_SINT32", name_len) == 0) RETURN_LONG(17);
if (strncmp(name, "TYPE_SINT64", name_len) == 0) RETURN_LONG(18);
zend_throw_exception(
NULL,
"Enum Google\\Protobuf\\Field_Kind has no value "
"defined for name %s.",
name,
0 TSRMLS_CC);
}
// -----------------------------------------------------------------------------
// NullValue
// -----------------------------------------------------------------------------
static zend_function_entry null_value_methods[] = {
PHP_ME(NullValue, name, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(NullValue, value, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
{NULL, NULL, NULL}
};
@ -962,11 +1107,51 @@ PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\NullValue",
"NULL_VALUE", 10, 0 TSRMLS_CC);
PHP_PROTO_INIT_ENUMCLASS_END
PHP_METHOD(NullValue, name) {
PHP_PROTO_LONG value;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) ==
FAILURE) {
return;
}
switch (value) {
case 0:
PHP_PROTO_RETURN_STRING("NULL_VALUE", 1);
default:
zend_throw_exception(
NULL,
"Enum Google\\Protobuf\\NullValue has no name "
"defined for value %d.",
value,
0 TSRMLS_CC);
}
}
PHP_METHOD(NullValue, value) {
char *name = NULL;
PHP_PROTO_SIZE name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) ==
FAILURE) {
return;
}
if (strncmp(name, "NULL_VALUE", name_len) == 0) RETURN_LONG(0);
zend_throw_exception(
NULL,
"Enum Google\\Protobuf\\NullValue has no value "
"defined for name %s.",
name,
0 TSRMLS_CC);
}
// -----------------------------------------------------------------------------
// Syntax
// -----------------------------------------------------------------------------
static zend_function_entry syntax_methods[] = {
PHP_ME(Syntax, name, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(Syntax, value, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
{NULL, NULL, NULL}
};
@ -981,7 +1166,46 @@ PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Syntax",
"SYNTAX_PROTO3", 13, 1 TSRMLS_CC);
PHP_PROTO_INIT_ENUMCLASS_END
PHP_METHOD(Syntax, name) {
PHP_PROTO_LONG value;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) ==
FAILURE) {
return;
}
switch (value) {
case 0:
PHP_PROTO_RETURN_STRING("SYNTAX_PROTO2", 1);
case 1:
PHP_PROTO_RETURN_STRING("SYNTAX_PROTO3", 1);
default:
zend_throw_exception(
NULL,
"Enum Google\\Protobuf\\Syntax has no name "
"defined for value %d.",
value,
0 TSRMLS_CC);
}
}
PHP_METHOD(Syntax, value) {
char *name = NULL;
PHP_PROTO_SIZE name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) ==
FAILURE) {
return;
}
if (strncmp(name, "SYNTAX_PROTO2", name_len) == 0) RETURN_LONG(0);
if (strncmp(name, "SYNTAX_PROTO3", name_len) == 0) RETURN_LONG(1);
zend_throw_exception(
NULL,
"Enum Google\\Protobuf\\Syntax has no value "
"defined for name %s.",
name,
0 TSRMLS_CC);
}
// -----------------------------------------------------------------------------
// Define message

View File

@ -1301,6 +1301,12 @@ PHP_METHOD(Field, setJsonName);
PHP_METHOD(Field, getDefaultValue);
PHP_METHOD(Field, setDefaultValue);
PHP_METHOD(Field_Cardinality, name);
PHP_METHOD(Field_Cardinality, value);
PHP_METHOD(Field_Kind, name);
PHP_METHOD(Field_Kind, value);
PHP_METHOD(FloatValue, __construct);
PHP_METHOD(FloatValue, getValue);
PHP_METHOD(FloatValue, setValue);
@ -1341,6 +1347,9 @@ PHP_METHOD(Mixin, setName);
PHP_METHOD(Mixin, getRoot);
PHP_METHOD(Mixin, setRoot);
PHP_METHOD(NullValue, name);
PHP_METHOD(NullValue, value);
PHP_METHOD(Option, __construct);
PHP_METHOD(Option, getName);
PHP_METHOD(Option, setName);
@ -1359,6 +1368,9 @@ PHP_METHOD(Struct, __construct);
PHP_METHOD(Struct, getFields);
PHP_METHOD(Struct, setFields);
PHP_METHOD(Syntax, name);
PHP_METHOD(Syntax, value);
PHP_METHOD(Type, __construct);
PHP_METHOD(Type, getName);
PHP_METHOD(Type, setName);

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf\Field;
use UnexpectedValueException;
/**
* Whether a field is optional, required, or repeated.
*
@ -35,6 +37,32 @@ class Cardinality
* Generated from protobuf enum <code>CARDINALITY_REPEATED = 3;</code>
*/
const CARDINALITY_REPEATED = 3;
private static $valueToName = [
self::CARDINALITY_UNKNOWN => 'CARDINALITY_UNKNOWN',
self::CARDINALITY_OPTIONAL => 'CARDINALITY_OPTIONAL',
self::CARDINALITY_REQUIRED => 'CARDINALITY_REQUIRED',
self::CARDINALITY_REPEATED => 'CARDINALITY_REPEATED',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}
// Adding a class alias for backwards compatibility with the previous class name.

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf\Field;
use UnexpectedValueException;
/**
* Basic field types.
*
@ -125,6 +127,47 @@ class Kind
* Generated from protobuf enum <code>TYPE_SINT64 = 18;</code>
*/
const TYPE_SINT64 = 18;
private static $valueToName = [
self::TYPE_UNKNOWN => 'TYPE_UNKNOWN',
self::TYPE_DOUBLE => 'TYPE_DOUBLE',
self::TYPE_FLOAT => 'TYPE_FLOAT',
self::TYPE_INT64 => 'TYPE_INT64',
self::TYPE_UINT64 => 'TYPE_UINT64',
self::TYPE_INT32 => 'TYPE_INT32',
self::TYPE_FIXED64 => 'TYPE_FIXED64',
self::TYPE_FIXED32 => 'TYPE_FIXED32',
self::TYPE_BOOL => 'TYPE_BOOL',
self::TYPE_STRING => 'TYPE_STRING',
self::TYPE_GROUP => 'TYPE_GROUP',
self::TYPE_MESSAGE => 'TYPE_MESSAGE',
self::TYPE_BYTES => 'TYPE_BYTES',
self::TYPE_UINT32 => 'TYPE_UINT32',
self::TYPE_ENUM => 'TYPE_ENUM',
self::TYPE_SFIXED32 => 'TYPE_SFIXED32',
self::TYPE_SFIXED64 => 'TYPE_SFIXED64',
self::TYPE_SINT32 => 'TYPE_SINT32',
self::TYPE_SINT64 => 'TYPE_SINT64',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}
// Adding a class alias for backwards compatibility with the previous class name.

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf\Internal\FieldDescriptorProto;
use UnexpectedValueException;
/**
* Protobuf type <code>google.protobuf.FieldDescriptorProto.Label</code>
*/
@ -23,6 +25,31 @@ class Label
* Generated from protobuf enum <code>LABEL_REPEATED = 3;</code>
*/
const LABEL_REPEATED = 3;
private static $valueToName = [
self::LABEL_OPTIONAL => 'LABEL_OPTIONAL',
self::LABEL_REQUIRED => 'LABEL_REQUIRED',
self::LABEL_REPEATED => 'LABEL_REPEATED',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}
// Adding a class alias for backwards compatibility with the previous class name.

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf\Internal\FieldDescriptorProto;
use UnexpectedValueException;
/**
* Protobuf type <code>google.protobuf.FieldDescriptorProto.Type</code>
*/
@ -103,6 +105,46 @@ class Type
* Generated from protobuf enum <code>TYPE_SINT64 = 18;</code>
*/
const TYPE_SINT64 = 18;
private static $valueToName = [
self::TYPE_DOUBLE => 'TYPE_DOUBLE',
self::TYPE_FLOAT => 'TYPE_FLOAT',
self::TYPE_INT64 => 'TYPE_INT64',
self::TYPE_UINT64 => 'TYPE_UINT64',
self::TYPE_INT32 => 'TYPE_INT32',
self::TYPE_FIXED64 => 'TYPE_FIXED64',
self::TYPE_FIXED32 => 'TYPE_FIXED32',
self::TYPE_BOOL => 'TYPE_BOOL',
self::TYPE_STRING => 'TYPE_STRING',
self::TYPE_GROUP => 'TYPE_GROUP',
self::TYPE_MESSAGE => 'TYPE_MESSAGE',
self::TYPE_BYTES => 'TYPE_BYTES',
self::TYPE_UINT32 => 'TYPE_UINT32',
self::TYPE_ENUM => 'TYPE_ENUM',
self::TYPE_SFIXED32 => 'TYPE_SFIXED32',
self::TYPE_SFIXED64 => 'TYPE_SFIXED64',
self::TYPE_SINT32 => 'TYPE_SINT32',
self::TYPE_SINT64 => 'TYPE_SINT64',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}
// Adding a class alias for backwards compatibility with the previous class name.

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf\Internal\FieldOptions;
use UnexpectedValueException;
/**
* Protobuf type <code>google.protobuf.FieldOptions.CType</code>
*/
@ -23,6 +25,31 @@ class CType
* Generated from protobuf enum <code>STRING_PIECE = 2;</code>
*/
const STRING_PIECE = 2;
private static $valueToName = [
self::STRING => 'STRING',
self::CORD => 'CORD',
self::STRING_PIECE => 'STRING_PIECE',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}
// Adding a class alias for backwards compatibility with the previous class name.

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf\Internal\FieldOptions;
use UnexpectedValueException;
/**
* Protobuf type <code>google.protobuf.FieldOptions.JSType</code>
*/
@ -27,6 +29,31 @@ class JSType
* Generated from protobuf enum <code>JS_NUMBER = 2;</code>
*/
const JS_NUMBER = 2;
private static $valueToName = [
self::JS_NORMAL => 'JS_NORMAL',
self::JS_STRING => 'JS_STRING',
self::JS_NUMBER => 'JS_NUMBER',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}
// Adding a class alias for backwards compatibility with the previous class name.

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf\Internal\FileOptions;
use UnexpectedValueException;
/**
* Generated classes can be optimized for speed or code size.
*
@ -29,6 +31,31 @@ class OptimizeMode
* Generated from protobuf enum <code>LITE_RUNTIME = 3;</code>
*/
const LITE_RUNTIME = 3;
private static $valueToName = [
self::SPEED => 'SPEED',
self::CODE_SIZE => 'CODE_SIZE',
self::LITE_RUNTIME => 'LITE_RUNTIME',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}
// Adding a class alias for backwards compatibility with the previous class name.

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf\Internal\MethodOptions;
use UnexpectedValueException;
/**
* Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
* or neither? HTTP based RPC implementation may choose GET verb for safe
@ -29,6 +31,31 @@ class IdempotencyLevel
* Generated from protobuf enum <code>IDEMPOTENT = 2;</code>
*/
const IDEMPOTENT = 2;
private static $valueToName = [
self::IDEMPOTENCY_UNKNOWN => 'IDEMPOTENCY_UNKNOWN',
self::NO_SIDE_EFFECTS => 'NO_SIDE_EFFECTS',
self::IDEMPOTENT => 'IDEMPOTENT',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}
// Adding a class alias for backwards compatibility with the previous class name.

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf;
use UnexpectedValueException;
/**
* `NullValue` is a singleton enumeration to represent the null value for the
* `Value` type union.
@ -19,5 +21,28 @@ class NullValue
* Generated from protobuf enum <code>NULL_VALUE = 0;</code>
*/
const NULL_VALUE = 0;
private static $valueToName = [
self::NULL_VALUE => 'NULL_VALUE',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}

View File

@ -4,6 +4,8 @@
namespace Google\Protobuf;
use UnexpectedValueException;
/**
* The syntax in which a protocol buffer element is defined.
*
@ -23,5 +25,29 @@ class Syntax
* Generated from protobuf enum <code>SYNTAX_PROTO3 = 1;</code>
*/
const SYNTAX_PROTO3 = 1;
private static $valueToName = [
self::SYNTAX_PROTO2 => 'SYNTAX_PROTO2',
self::SYNTAX_PROTO3 => 'SYNTAX_PROTO3',
];
public static function name($value)
{
if (!isset(self::$valueToName[$value])) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no name defined for value %s', __CLASS__, $value));
}
return self::$valueToName[$value];
}
public static function value($name)
{
$const = __CLASS__ . '::' . strtoupper($name);
if (!defined($const)) {
throw new UnexpectedValueException(sprintf(
'Enum %s has no value defined for name %s', __CLASS__, $name));
}
return constant($const);
}
}

View File

@ -232,6 +232,28 @@ class GeneratedClassTest extends TestBase
// Set string.
$m->setOptionalEnum("1");
$this->assertEquals(TestEnum::ONE, $m->getOptionalEnum());
// Test Enum methods
$this->assertEquals('ONE', TestEnum::name(1));
$this->assertEquals(1, TestEnum::value('ONE'));
}
/**
* @expectedException UnexpectedValueException
* @expectedExceptionMessage Enum Foo\TestEnum has no name defined for value -1
*/
public function testInvalidEnumValueThrowsException()
{
TestEnum::name(-1);
}
/**
* @expectedException UnexpectedValueException
* @expectedExceptionMessage Enum Foo\TestEnum has no value defined for name DOES_NOT_EXIST
*/
public function testInvalidEnumNameThrowsException()
{
TestEnum::value('DOES_NOT_EXIST');
}
public function testNestedEnum()

View File

@ -392,4 +392,27 @@ class WellKnownTest extends TestBase {
$m->setValue("a");
$this->assertSame("a", $m->getValue());
}
/**
* @dataProvider enumNameValueConversionDataProvider
*/
public function testEnumNameValueConversion($class)
{
$reflectionClass = new ReflectionClass($class);
$constants = $reflectionClass->getConstants();
foreach ($constants as $k => $v) {
$this->assertSame($k, $class::name($v));
$this->assertSame($v, $class::value($k));
}
}
public function enumNameValueConversionDataProvider()
{
return [
['\Google\Protobuf\Field\Cardinality'],
['\Google\Protobuf\Field\Kind'],
['\Google\Protobuf\NullValue'],
['\Google\Protobuf\Syntax'],
];
}
}

View File

@ -1146,14 +1146,18 @@ void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
printer.Print(
"namespace ^name^;\n\n",
"name", fullname.substr(0, lastindex));
// We only need this 'use' statement if the enum has a namespace.
// Otherwise, we get a warning that the use statement has no effect.
printer.Print("use UnexpectedValueException;\n\n");
}
GenerateEnumDocComment(&printer, en, is_descriptor);
if (lastindex != string::npos) {
fullname = fullname.substr(lastindex + 1);
}
GenerateEnumDocComment(&printer, en, is_descriptor);
printer.Print(
"class ^name^\n"
"{\n",
@ -1168,6 +1172,53 @@ void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
"number", IntToString(value->number()));
}
printer.Print("\nprivate static $valueToName = [\n");
Indent(&printer);
for (int i = 0; i < en->value_count(); i++) {
const EnumValueDescriptor* value = en->value(i);
printer.Print("self::^name^ => '^name^',\n",
"name", ConstantNamePrefix(value->name()) + value->name());
}
Outdent(&printer);
printer.Print("];\n");
printer.Print(
"\npublic static function name($value)\n"
"{\n");
Indent(&printer);
printer.Print("if (!isset(self::$valueToName[$value])) {\n");
Indent(&printer);
printer.Print("throw new UnexpectedValueException(sprintf(\n");
Indent(&printer);
Indent(&printer);
printer.Print("'Enum %s has no name defined for value %s', __CLASS__, $value));\n");
Outdent(&printer);
Outdent(&printer);
Outdent(&printer);
printer.Print("}\n"
"return self::$valueToName[$value];\n");
Outdent(&printer);
printer.Print("}\n\n");
printer.Print(
"\npublic static function value($name)\n"
"{\n");
Indent(&printer);
printer.Print("$const = __CLASS__ . '::' . strtoupper($name);\n"
"if (!defined($const)) {\n");
Indent(&printer);
printer.Print("throw new UnexpectedValueException(sprintf(\n");
Indent(&printer);
Indent(&printer);
printer.Print("'Enum %s has no value defined for name %s', __CLASS__, $name));\n");
Outdent(&printer);
Outdent(&printer);
Outdent(&printer);
printer.Print("}\n"
"return constant($const);\n");
Outdent(&printer);
printer.Print("}\n");
Outdent(&printer);
printer.Print("}\n\n");