Skip to content

Commit f648bd9

Browse files
committed
Serialization
1 parent fe99bf0 commit f648bd9

File tree

15 files changed

+354
-66
lines changed

15 files changed

+354
-66
lines changed

ext/standard/url.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ static zend_result parse_url_read_fragment(const uri_internal_t *internal_uri, z
430430

431431
static zend_result parse_url_init_parser(void)
432432
{
433-
zend_hash_init(&parse_url_property_handlers, 0, NULL, NULL, true);
433+
zend_hash_init(&parse_url_property_handlers, 8, NULL, NULL, true);
434434

435435
URI_REGISTER_PROPERTY_READ_HANDLER(&parse_url_property_handlers, ZSTR_KNOWN(ZEND_STR_SCHEME), parse_url_read_scheme);
436436
URI_REGISTER_PROPERTY_READ_HANDLER(&parse_url_property_handlers, ZSTR_KNOWN(ZEND_STR_USER), parse_url_read_user);

ext/uri/php_lexbor.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ static zend_result lexbor_init_parser(void)
254254
lexbor_parser = parser;
255255
lexbor_urls = 0;
256256

257-
zend_hash_init(&lexbor_property_handlers, 0, NULL, NULL, true);
257+
zend_hash_init(&lexbor_property_handlers, 8, NULL, NULL, true);
258258

259259
URI_REGISTER_PROPERTY_READ_WRITE_HANDLER(&lexbor_property_handlers, ZSTR_KNOWN(ZEND_STR_SCHEME), lexbor_read_scheme, lexbor_write_scheme);
260260
URI_REGISTER_PROPERTY_READ_WRITE_HANDLER(&lexbor_property_handlers, ZSTR_KNOWN(ZEND_STR_USER), lexbor_read_user, lexbor_write_user);

ext/uri/php_uri.c

Lines changed: 151 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,51 @@ static uri_handler_t *uri_handler_by_name(const char *handler_name, size_t handl
4444
return zend_hash_str_find_ptr(&uri_handlers, handler_name, handler_name_len);
4545
}
4646

47+
static HashTable *uri_get_properties(zend_object *object, bool is_debug)
48+
{
49+
uri_internal_t *internal_uri = uri_internal_from_obj(object);
50+
ZEND_ASSERT(internal_uri != NULL);
51+
if (UNEXPECTED(internal_uri->uri == NULL)) {
52+
if (!is_debug) {
53+
zend_throw_error(NULL, "%s object is not correctly initialized", ZSTR_VAL(object->ce->name));
54+
}
55+
return NULL;
56+
}
57+
58+
zend_string *string_key;
59+
uri_property_handler_t *property_handler;
60+
61+
HashTable *std_properties = zend_std_get_properties(object);
62+
HashTable *result = zend_array_dup(std_properties);
63+
64+
zend_string *object_str = is_debug ? ZSTR_INIT_LITERAL("(object value omitted)", false) : NULL;
65+
66+
const HashTable *property_handlers = internal_uri->handler->property_handlers;
67+
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(property_handlers, string_key, property_handler) {
68+
zval value;
69+
70+
ZEND_ASSERT(string_key != NULL);
71+
72+
if (property_handler->read_func(internal_uri, &value) == FAILURE) {
73+
continue;
74+
}
75+
76+
if (is_debug && Z_TYPE(value) == IS_OBJECT) {
77+
zval_ptr_dtor(&value);
78+
ZVAL_NEW_STR(&value, object_str);
79+
zend_string_addref(object_str);
80+
}
81+
82+
zend_hash_update(result, string_key, &value);
83+
} ZEND_HASH_FOREACH_END();
84+
85+
if (is_debug) {
86+
zend_string_release_ex(object_str, false);
87+
}
88+
89+
return result;
90+
}
91+
4792
PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name)
4893
{
4994
if (uri_handler_name == NULL) {
@@ -75,7 +120,7 @@ PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_stri
75120

76121
static zend_result php_uri_get_property(const uri_internal_t *internal_uri, zend_string *name, zval *zv)
77122
{
78-
uri_property_handler_t *property_handler = uri_property_handler_from_uri_handler(internal_uri->handler, name);
123+
uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, name);
79124
if (property_handler == NULL) {
80125
return FAILURE;
81126
}
@@ -327,6 +372,83 @@ PHP_METHOD(Uri_Rfc3986Uri, __toString)
327372
RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri));
328373
}
329374

375+
PHP_METHOD(Uri_Rfc3986Uri, __serialize)
376+
{
377+
ZEND_PARSE_PARAMETERS_NONE();
378+
379+
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
380+
uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
381+
URI_CHECK_INITIALIZATION_RETURN_THROWS(internal_uri, this_object);
382+
383+
HashTable *ht = uri_get_properties(this_object, false);
384+
ZVAL_ARR(return_value, ht);
385+
}
386+
387+
static void uri_restore_custom_properties(zend_object *object, uri_internal_t *internal_uri, HashTable *ht)
388+
{
389+
zend_string *prop_name;
390+
zval *prop_val;
391+
392+
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, prop_name, prop_val) {
393+
if (!prop_name || Z_TYPE_P(prop_val) == IS_REFERENCE || uri_property_handler_from_internal_uri(internal_uri, prop_name)) {
394+
continue;
395+
}
396+
397+
zend_update_property_ex(object->ce, object, prop_name, prop_val);
398+
if (EG(exception)) {
399+
break;
400+
}
401+
} ZEND_HASH_FOREACH_END();
402+
}
403+
404+
PHP_METHOD(Uri_Rfc3986Uri, __unserialize)
405+
{
406+
HashTable *ht;
407+
408+
ZEND_PARSE_PARAMETERS_START(1, 1)
409+
Z_PARAM_ARRAY_HT(ht)
410+
ZEND_PARSE_PARAMETERS_END();
411+
412+
zend_object *object = Z_OBJ_P(ZEND_THIS);
413+
uri_internal_t *internal_uri = uri_internal_from_obj(object);
414+
415+
/*if (!php_date_initialize_from_hash(&dateobj, myht)) {
416+
zend_throw_error(NULL, "Invalid serialization data for DateTime object");
417+
RETURN_THROWS();
418+
}*/
419+
420+
zend_string *str = zend_string_init("https://example.com", sizeof("https://example.com") - 1, false);
421+
422+
internal_uri->handler = uri_handler_by_name("rfc3986", sizeof("rfc3986") - 1);
423+
internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, NULL);
424+
425+
uri_restore_custom_properties(object, internal_uri, ht);
426+
}
427+
428+
PHP_METHOD(Uri_WhatWgUri, __unserialize)
429+
{
430+
HashTable *ht;
431+
432+
ZEND_PARSE_PARAMETERS_START(1, 1)
433+
Z_PARAM_ARRAY_HT(ht)
434+
ZEND_PARSE_PARAMETERS_END();
435+
436+
zend_object *object = Z_OBJ_P(ZEND_THIS);
437+
uri_internal_t *internal_uri = uri_internal_from_obj(object);
438+
439+
/*if (!php_date_initialize_from_hash(&dateobj, myht)) {
440+
zend_throw_error(NULL, "Invalid serialization data for DateTime object");
441+
RETURN_THROWS();
442+
}*/
443+
444+
zend_string *str = zend_string_init("https://example.com", sizeof("https://example.com") - 1, false);
445+
446+
internal_uri->handler = uri_handler_by_name("whatwg", sizeof("whatwg") - 1);
447+
internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, NULL);
448+
449+
uri_restore_custom_properties(object, internal_uri, ht);
450+
}
451+
330452
static zend_object *uri_create_object_handler(zend_class_entry *class_type)
331453
{
332454
uri_object_t *uri_object = zend_object_alloc(sizeof(uri_object_t), class_type);
@@ -366,7 +488,7 @@ static int uri_has_property_handler(zend_object *object, zend_string *name, int
366488
}
367489

368490
uri_property_handler_t *property_handler = zend_hash_find_ptr(internal_uri->handler->property_handlers, name);
369-
if (!property_handler) {
491+
if (UNEXPECTED(property_handler == NULL)) {
370492
return zend_std_has_property(object, name, check_empty, cache_slot);
371493
}
372494

@@ -400,7 +522,7 @@ static zval *uri_read_property_handler(zend_object *object, zend_string *name, i
400522
uri_internal_t *internal_uri = uri_internal_from_obj(object);
401523
URI_CHECK_INITIALIZATION_RETURN(internal_uri, object, &EG(uninitialized_zval));
402524

403-
uri_property_handler_t *property_handler = uri_property_handler_from_uri_handler(internal_uri->handler, name);
525+
uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, name);
404526
if (UNEXPECTED(property_handler == NULL)) {
405527
return zend_std_read_property(object, name, type, cache_slot, rv);
406528
}
@@ -426,39 +548,38 @@ static zval *uri_write_property_handler(zend_object *object, zend_string *name,
426548
uri_internal_t *internal_uri = uri_internal_from_obj(object);
427549
URI_CHECK_INITIALIZATION_RETURN(internal_uri, object, &EG(error_zval));
428550

429-
uri_property_handler_t *property_handler = uri_property_handler_from_uri_handler(internal_uri->handler, name);
430-
if (UNEXPECTED(property_handler != NULL)) {
431-
zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
432-
return &EG(error_zval);
551+
uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, name);
552+
if (UNEXPECTED(property_handler == NULL)) {
553+
return zend_std_write_property(object, name, value, cache_slot);
433554
}
434555

435-
return zend_std_write_property(object, name, value, cache_slot);
556+
zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
557+
return &EG(error_zval);
436558
}
437559

438560
static zval *uri_get_property_ptr_ptr_handler(zend_object *object, zend_string *name, int type, void **cache_slot)
439561
{
440562
const uri_internal_t *internal_uri = uri_internal_from_obj(object);
441563
URI_CHECK_INITIALIZATION_RETURN(internal_uri, object, NULL);
442564

443-
if (uri_property_handler_from_uri_handler(internal_uri->handler, name)) {
444-
zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
445-
return &EG(error_zval);
565+
if (UNEXPECTED(uri_property_handler_from_internal_uri(internal_uri, name) == NULL)) {
566+
return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
446567
}
447568

448-
return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
569+
zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
570+
return &EG(error_zval);
449571
}
450572

451573
static void uri_unset_property_handler(zend_object *object, zend_string *name, void **cache_slot)
452574
{
453575
uri_internal_t *internal_uri = uri_internal_from_obj(object);
454576
URI_CHECK_INITIALIZATION_RETURN_VOID(internal_uri, object);
455577

456-
if (uri_property_handler_from_uri_handler(internal_uri->handler, name)) {
457-
zend_throw_error(NULL, "Cannot unset readonly property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
458-
return;
578+
if (UNEXPECTED(uri_property_handler_from_internal_uri(internal_uri, name) == NULL)) {
579+
zend_std_unset_property(object, name, cache_slot);
459580
}
460581

461-
zend_std_unset_property(object, name, cache_slot);
582+
zend_throw_error(NULL, "Cannot unset readonly property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
462583
}
463584

464585
static zend_object *uri_clone_obj_handler(zend_object *object)
@@ -489,46 +610,9 @@ static zend_object *uri_clone_obj_handler(zend_object *object)
489610

490611
static HashTable *uri_get_debug_info_handler(zend_object *object, int *is_temp)
491612
{
492-
HashTable *debug_info, *std_properties;
493-
494-
uri_internal_t *internal_uri = uri_internal_from_obj(object);
495-
ZEND_ASSERT(internal_uri != NULL);
496-
if (UNEXPECTED(internal_uri->uri == NULL)) {
497-
return NULL;
498-
}
499-
500-
const HashTable *property_handlers = internal_uri->handler->property_handlers;
501-
zend_string *string_key;
502-
uri_property_handler_t *property_handler;
503-
504613
*is_temp = 1;
505614

506-
std_properties = zend_std_get_properties(object);
507-
debug_info = zend_array_dup(std_properties);
508-
509-
zend_string *object_str = ZSTR_INIT_LITERAL("(object value omitted)", false);
510-
511-
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(property_handlers, string_key, property_handler) {
512-
zval value;
513-
514-
ZEND_ASSERT(string_key != NULL);
515-
516-
if (property_handler->read_func(internal_uri, &value) == FAILURE) {
517-
continue;
518-
}
519-
520-
if (Z_TYPE(value) == IS_OBJECT) {
521-
zval_ptr_dtor(&value);
522-
ZVAL_NEW_STR(&value, object_str);
523-
zend_string_addref(object_str);
524-
}
525-
526-
zend_hash_update(debug_info, string_key, &value);
527-
} ZEND_HASH_FOREACH_END();
528-
529-
zend_string_release_ex(object_str, false);
530-
531-
return debug_info;
615+
return uri_get_properties(object, true);
532616
}
533617

534618
static HashTable *uri_get_gc_handler(zend_object *object, zval **table, int *n)
@@ -539,6 +623,18 @@ static HashTable *uri_get_gc_handler(zend_object *object, zval **table, int *n)
539623
return zend_std_get_properties(object);
540624
}
541625

626+
static HashTable *uri_get_properties_for_handler(zend_object *object, zend_prop_purpose purpose)
627+
{
628+
switch (purpose) {
629+
case ZEND_PROP_PURPOSE_ARRAY_CAST:
630+
case ZEND_PROP_PURPOSE_VAR_EXPORT:
631+
case ZEND_PROP_PURPOSE_JSON:
632+
return uri_get_properties(object, false);
633+
default:
634+
return zend_std_get_properties_for(object, purpose);
635+
}
636+
}
637+
542638
PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers)
543639
{
544640
ce->create_object = uri_create_object_handler;
@@ -554,6 +650,7 @@ PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zen
554650
object_handlers->clone_obj = uri_clone_obj_handler;
555651
object_handlers->get_debug_info = uri_get_debug_info_handler;
556652
object_handlers->get_gc = uri_get_gc_handler;
653+
object_handlers->get_properties_for = uri_get_properties_for_handler;
557654
}
558655

559656
void uri_register_symbols(void)

ext/uri/php_uri.stub.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ public function getFragment(): ?string {}
166166
public function withFragment(?string $fragment): static {}
167167

168168
public function __toString(): string {}
169+
170+
public function __serialize(): array;
171+
172+
public function __unserialize(array $data): void;
169173
}
170174

171175
/** @strict-properties */
@@ -244,4 +248,9 @@ public function withFragment(?string $fragment): static {}
244248

245249
/** @implementation-alias Uri\Rfc3986Uri::__toString */
246250
public function __toString(): string {}
251+
252+
/** @implementation-alias Uri\Rfc3986Uri::__serialize */
253+
public function __serialize(): array {}
254+
255+
public function __unserialize(array $data): void {}
247256
}

ext/uri/php_uri_arginfo.h

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)