Skip to content

Commit 4be9669

Browse files
committed
PHPC-460: Decimal128 serialization and var_export
1 parent 06ee895 commit 4be9669

File tree

5 files changed

+241
-18
lines changed

5 files changed

+241
-18
lines changed

php_phongo.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,7 @@ void php_phongo_new_decimal128(zval *object, const bson_decimal128_t *decimal TS
20922092

20932093
intern = Z_DECIMAL128_OBJ_P(object);
20942094
memcpy(&intern->decimal, decimal, sizeof(bson_decimal128_t));
2095+
intern->initialized = true;
20952096
} /* }}} */
20962097

20972098
void php_phongo_new_regex_from_regex_and_options(zval *object, const char *pattern, const char *flags TSRMLS_DC) /* {{{ */

php_phongo_structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ typedef struct {
161161

162162
typedef struct {
163163
PHONGO_ZEND_OBJECT_PRE
164+
bool initialized;
164165
bson_decimal128_t decimal;
165166
PHONGO_ZEND_OBJECT_POST
166167
} php_phongo_decimal128_t;

src/BSON/Decimal128.c

Lines changed: 108 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,37 @@ PHONGO_API zend_class_entry *php_phongo_decimal128_ce;
4646

4747
zend_object_handlers php_phongo_handler_decimal128;
4848

49+
/* Initialize the object from a string and return whether it was successful. */
50+
static bool php_phongo_decimal128_init(php_phongo_decimal128_t *intern, const char *value)
51+
{
52+
if (bson_decimal128_from_string(value, &intern->decimal)) {
53+
intern->initialized = true;
54+
55+
return true;
56+
}
57+
58+
return false;
59+
}
60+
61+
/* Initialize the object from a HashTable and return whether it was successful. */
62+
static bool php_phongo_decimal128_init_from_hash(php_phongo_decimal128_t *intern, HashTable *props)
63+
{
64+
#if PHP_VERSION_ID >= 70000
65+
zval *dec;
66+
67+
if ((dec = zend_hash_str_find(props, "dec", sizeof("dec")-1)) && Z_TYPE_P(dec) == IS_STRING) {
68+
return php_phongo_decimal128_init(intern, Z_STRVAL_P(dec));
69+
}
70+
#else
71+
zval **dec;
72+
73+
if (zend_hash_find(props, "dec", sizeof("dec"), (void**) &dec) == SUCCESS && Z_TYPE_PP(dec) == IS_STRING) {
74+
return php_phongo_decimal128_init(intern, Z_STRVAL_PP(dec));
75+
}
76+
#endif
77+
return false;
78+
}
79+
4980
/* {{{ proto BSON\Decimal128 Decimal128::__construct(string $value)
5081
Construct a new BSON Decimal128 type */
5182
PHP_METHOD(Decimal128, __construct)
@@ -65,9 +96,31 @@ PHP_METHOD(Decimal128, __construct)
6596
}
6697
zend_restore_error_handling(&error_handling TSRMLS_CC);
6798

68-
if ( ! bson_decimal128_from_string(value, &intern->decimal)) {
99+
if (!php_phongo_decimal128_init(intern, value)) {
69100
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Error parsing decimal string: %s", value);
70-
return;
101+
}
102+
}
103+
/* }}} */
104+
105+
/* {{{ proto Decimal128::__set_state(array $properties)
106+
*/
107+
PHP_METHOD(Decimal128, __set_state)
108+
{
109+
php_phongo_decimal128_t *intern;
110+
HashTable *props;
111+
zval *array;
112+
113+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
114+
RETURN_FALSE;
115+
}
116+
117+
object_init_ex(return_value, php_phongo_decimal128_ce);
118+
119+
intern = Z_DECIMAL128_OBJ_P(return_value);
120+
props = Z_ARRVAL_P(array);
121+
122+
if (!php_phongo_decimal128_init_from_hash(intern, props)) {
123+
php_error(E_ERROR, "Invalid serialization data for Decimal128 object");
71124
}
72125
}
73126
/* }}} */
@@ -91,21 +144,44 @@ PHP_METHOD(Decimal128, __toString)
91144
}
92145
/* }}} */
93146

147+
/* {{{ proto Decimal128::__wakeup()
148+
*/
149+
PHP_METHOD(Decimal128, __wakeup)
150+
{
151+
php_phongo_decimal128_t *intern;
152+
HashTable *props;
153+
154+
if (zend_parse_parameters_none() == FAILURE) {
155+
return;
156+
}
157+
158+
intern = Z_DECIMAL128_OBJ_P(getThis());
159+
props = zend_std_get_properties(getThis() TSRMLS_CC);
160+
161+
if (!php_phongo_decimal128_init_from_hash(intern, props)) {
162+
php_error(E_ERROR, "Invalid serialization data for Decimal128 object");
163+
}
164+
}
165+
/* }}} */
94166

95167
/* {{{ BSON\Decimal128 */
96168

97169
ZEND_BEGIN_ARG_INFO_EX(ai_Decimal128___construct, 0, 0, 2)
98170
ZEND_ARG_INFO(0, value)
99171
ZEND_END_ARG_INFO();
100172

101-
ZEND_BEGIN_ARG_INFO_EX(ai_Decimal128___toString, 0, 0, 0)
173+
ZEND_BEGIN_ARG_INFO_EX(ai_Decimal128___set_state, 0, 0, 1)
174+
ZEND_ARG_ARRAY_INFO(0, properties, 0)
102175
ZEND_END_ARG_INFO();
103176

177+
ZEND_BEGIN_ARG_INFO_EX(ai_Decimal128_void, 0, 0, 0)
178+
ZEND_END_ARG_INFO();
104179

105180
static zend_function_entry php_phongo_decimal128_me[] = {
106181
PHP_ME(Decimal128, __construct, ai_Decimal128___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
107-
PHP_ME(Decimal128, __toString, ai_Decimal128___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
108-
PHP_ME(Manager, __wakeUp, NULL, ZEND_ACC_PUBLIC)
182+
PHP_ME(Decimal128, __set_state, ai_Decimal128___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
183+
PHP_ME(Decimal128, __toString, ai_Decimal128_void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
184+
PHP_ME(Decimal128, __wakeup, ai_Decimal128_void, ZEND_ACC_PUBLIC)
109185
PHP_FE_END
110186
};
111187

@@ -148,24 +224,39 @@ phongo_create_object_retval php_phongo_decimal128_create_object(zend_class_entry
148224
#endif
149225
} /* }}} */
150226

151-
HashTable *php_phongo_decimal128_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
227+
HashTable *php_phongo_decimal128_get_properties(zval *object TSRMLS_DC) /* {{{ */
152228
{
153229
php_phongo_decimal128_t *intern;
154-
char outbuf[BSON_DECIMAL128_STRING] = "";
155-
#if PHP_VERSION_ID >= 70000
156-
zval retval;
157-
#else
158-
zval retval = zval_used_for_init;
159-
#endif
230+
HashTable *props;
231+
char outbuf[BSON_DECIMAL128_STRING] = "";
160232

161233
intern = Z_DECIMAL128_OBJ_P(object);
162-
*is_temp = 1;
163-
array_init_size(&retval, 1);
234+
props = zend_std_get_properties(object TSRMLS_CC);
235+
236+
if (!intern->initialized) {
237+
return props;
238+
}
164239

165240
bson_decimal128_to_string(&intern->decimal, outbuf);
166-
ADD_ASSOC_STRING(&retval, "dec", outbuf);
167241

168-
return Z_ARRVAL(retval);
242+
#if PHP_VERSION_ID >= 70000
243+
{
244+
zval dec;
245+
246+
ZVAL_STRING(&dec, outbuf);
247+
zend_hash_str_update(props, "dec", sizeof("dec")-1, &dec);
248+
}
249+
#else
250+
{
251+
zval *dec;
252+
253+
MAKE_STD_ZVAL(dec);
254+
ZVAL_STRING(dec, outbuf, 1);
255+
zend_hash_update(props, "dec", sizeof("dec"), &dec, sizeof(dec), NULL);
256+
}
257+
#endif
258+
259+
return props;
169260
} /* }}} */
170261
/* }}} */
171262

@@ -179,12 +270,11 @@ PHP_MINIT_FUNCTION(Decimal128)
179270
php_phongo_decimal128_ce = zend_register_internal_class(&ce TSRMLS_CC);
180271
php_phongo_decimal128_ce->create_object = php_phongo_decimal128_create_object;
181272
PHONGO_CE_FINAL(php_phongo_decimal128_ce);
182-
PHONGO_CE_DISABLE_SERIALIZATION(php_phongo_decimal128_ce);
183273

184274
zend_class_implements(php_phongo_decimal128_ce TSRMLS_CC, 1, php_phongo_type_ce);
185275

186276
memcpy(&php_phongo_handler_decimal128, phongo_get_std_object_handlers(), sizeof(zend_object_handlers));
187-
php_phongo_handler_decimal128.get_debug_info = php_phongo_decimal128_get_debug_info;
277+
php_phongo_handler_decimal128.get_properties = php_phongo_decimal128_get_properties;
188278
#if PHP_VERSION_ID >= 70000
189279
php_phongo_handler_decimal128.free_obj = php_phongo_decimal128_free_object;
190280
php_phongo_handler_decimal128.offset = XtOffsetOf(php_phongo_decimal128_t, std);

tests/bson/bson-decimal128-005.phpt

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
--TEST--
2+
MongoDB\BSON\Decimal128 serialization
3+
--SKIPIF--
4+
<?php require __DIR__ . '/../utils/basic-skipif.inc'?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . '/../utils/basic.inc';
8+
9+
$tests = [
10+
'1234.5678',
11+
'-1234.5678',
12+
1234.56e-78,
13+
INF,
14+
NAN,
15+
];
16+
17+
foreach ($tests as $value) {
18+
var_dump($decimal = new MongoDB\BSON\Decimal128($value));
19+
var_dump($s = serialize($decimal));
20+
var_dump(unserialize($s));
21+
echo "\n";
22+
}
23+
24+
?>
25+
===DONE===
26+
<?php exit(0); ?>
27+
--EXPECTF--
28+
object(MongoDB\BSON\Decimal128)#%d (%d) {
29+
["dec"]=>
30+
string(9) "1234.5678"
31+
}
32+
string(61) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:9:"1234.5678";}"
33+
object(MongoDB\BSON\Decimal128)#%d (%d) {
34+
["dec"]=>
35+
string(9) "1234.5678"
36+
}
37+
38+
object(MongoDB\BSON\Decimal128)#%d (%d) {
39+
["dec"]=>
40+
string(10) "-1234.5678"
41+
}
42+
string(63) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:10:"-1234.5678";}"
43+
object(MongoDB\BSON\Decimal128)#%d (%d) {
44+
["dec"]=>
45+
string(10) "-1234.5678"
46+
}
47+
48+
object(MongoDB\BSON\Decimal128)#%d (%d) {
49+
["dec"]=>
50+
string(11) "1.23456E-75"
51+
}
52+
string(64) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:11:"1.23456E-75";}"
53+
object(MongoDB\BSON\Decimal128)#%d (%d) {
54+
["dec"]=>
55+
string(11) "1.23456E-75"
56+
}
57+
58+
object(MongoDB\BSON\Decimal128)#%d (%d) {
59+
["dec"]=>
60+
string(8) "Infinity"
61+
}
62+
string(60) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:8:"Infinity";}"
63+
object(MongoDB\BSON\Decimal128)#%d (%d) {
64+
["dec"]=>
65+
string(8) "Infinity"
66+
}
67+
68+
object(MongoDB\BSON\Decimal128)#%d (%d) {
69+
["dec"]=>
70+
string(3) "NaN"
71+
}
72+
string(55) "O:23:"MongoDB\BSON\Decimal128":1:{s:3:"dec";s:3:"NaN";}"
73+
object(MongoDB\BSON\Decimal128)#%d (%d) {
74+
["dec"]=>
75+
string(3) "NaN"
76+
}
77+
78+
===DONE===
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
--TEST--
2+
MongoDB\BSON\Decimal128::__set_state()
3+
--SKIPIF--
4+
<?php require __DIR__ . '/../utils/basic-skipif.inc'?>
5+
--FILE--
6+
<?php
7+
require_once __DIR__ . '/../utils/basic.inc';
8+
9+
$tests = [
10+
'1234.5678',
11+
'-1234.5678',
12+
'Infinity',
13+
'INF',
14+
'NaN',
15+
'NAN',
16+
];
17+
18+
foreach ($tests as $value) {
19+
var_export(MongoDB\BSON\Decimal128::__set_state([
20+
'dec' => $value,
21+
]));
22+
echo "\n\n";
23+
}
24+
25+
?>
26+
===DONE===
27+
<?php exit(0); ?>
28+
--EXPECT--
29+
MongoDB\BSON\Decimal128::__set_state(array(
30+
'dec' => '1234.5678',
31+
))
32+
33+
MongoDB\BSON\Decimal128::__set_state(array(
34+
'dec' => '-1234.5678',
35+
))
36+
37+
MongoDB\BSON\Decimal128::__set_state(array(
38+
'dec' => 'Infinity',
39+
))
40+
41+
MongoDB\BSON\Decimal128::__set_state(array(
42+
'dec' => 'Infinity',
43+
))
44+
45+
MongoDB\BSON\Decimal128::__set_state(array(
46+
'dec' => 'NaN',
47+
))
48+
49+
MongoDB\BSON\Decimal128::__set_state(array(
50+
'dec' => 'NaN',
51+
))
52+
53+
===DONE===

0 commit comments

Comments
 (0)