Skip to content

Commit 72c581b

Browse files
committed
Implement acyclic object tracking
Acyclic objects don't need to be added to the GC. We know an object is acyclic if all properties are typed as acyclic, and the object does not have any dynamic properties. This is possible to track at runtime with minimal overhead. Fixes GH-17127
1 parent 07cd468 commit 72c581b

29 files changed

+112
-2
lines changed

Zend/tests/gc/gc_045.phpt

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ class GlobalData
1111

1212
class Value
1313
{
14+
/* Force object to be added to GC, even though it is acyclic. */
15+
public $dummy;
16+
1417
public function __destruct()
1518
{
1619
new Bar();
@@ -19,6 +22,9 @@ class Value
1922

2023
class Bar
2124
{
25+
/* Force object to be added to GC, even though it is acyclic. */
26+
public $dummy;
27+
2228
public function __construct()
2329
{
2430
GlobalData::$bar = $this;

Zend/zend_API.c

+27
Original file line numberDiff line numberDiff line change
@@ -4494,6 +4494,27 @@ static zend_always_inline bool is_persistent_class(zend_class_entry *ce) {
44944494
&& ce->info.internal.module->type == MODULE_PERSISTENT;
44954495
}
44964496

4497+
static bool zend_type_may_be_cyclic(zend_type type)
4498+
{
4499+
if (!ZEND_TYPE_IS_SET(type)) {
4500+
return true;
4501+
}
4502+
4503+
if (!ZEND_TYPE_IS_COMPLEX(type)) {
4504+
return ZEND_TYPE_PURE_MASK(type) & (MAY_BE_OBJECT|MAY_BE_ARRAY);
4505+
} else if (ZEND_TYPE_IS_UNION(type)) {
4506+
zend_type *list_type;
4507+
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
4508+
if (zend_type_may_be_cyclic(*list_type)) {
4509+
return true;
4510+
}
4511+
} ZEND_TYPE_LIST_FOREACH_END();
4512+
return false;
4513+
}
4514+
4515+
return true;
4516+
}
4517+
44974518
ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type) /* {{{ */
44984519
{
44994520
zend_property_info *property_info, *property_info_ptr;
@@ -4506,6 +4527,12 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z
45064527
}
45074528
}
45084529

4530+
if (!(access_type & ZEND_ACC_STATIC)
4531+
&& !(ce->ce_flags & ZEND_ACC_MAY_BE_CYCLIC)
4532+
&& zend_type_may_be_cyclic(type)) {
4533+
ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
4534+
}
4535+
45094536
if (ce->type == ZEND_INTERNAL_CLASS) {
45104537
property_info = pemalloc(sizeof(zend_property_info), 1);
45114538
} else {

Zend/zend_closures.c

+3
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,9 @@ void zend_register_closure_ce(void) /* {{{ */
705705
zend_ce_closure = register_class_Closure();
706706
zend_ce_closure->create_object = zend_closure_new;
707707
zend_ce_closure->default_object_handlers = &closure_handlers;
708+
/* FIXME: Potentially improve during construction of closure? static closures
709+
* not binding by references can't be cyclic. */
710+
zend_ce_closure->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
708711

709712
memcpy(&closure_handlers, &std_object_handlers, sizeof(zend_object_handlers));
710713
closure_handlers.free_obj = zend_closure_free_storage;

Zend/zend_compile.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ typedef struct _zend_oparray_context {
267267
#define ZEND_ACC_PROTECTED_SET (1 << 11) /* | | X | */
268268
#define ZEND_ACC_PRIVATE_SET (1 << 12) /* | | X | */
269269
/* | | | */
270-
/* Class Flags (unused: 30,31) | | | */
270+
/* Class Flags (unused: 31) | | | */
271271
/* =========== | | | */
272272
/* | | | */
273273
/* Special class types | | | */
@@ -333,6 +333,9 @@ typedef struct _zend_oparray_context {
333333
/* Class cannot be serialized or unserialized | | | */
334334
#define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */
335335
/* | | | */
336+
/* Object may be the root of a cycle | | | */
337+
#define ZEND_ACC_MAY_BE_CYCLIC (1 << 30) /* X | | | */
338+
/* | | | */
336339
/* Function Flags (unused: 29-30) | | | */
337340
/* ============== | | | */
338341
/* | | | */

Zend/zend_fibers.c

+1
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,7 @@ void zend_register_fiber_ce(void)
11071107
zend_ce_fiber = register_class_Fiber();
11081108
zend_ce_fiber->create_object = zend_fiber_object_create;
11091109
zend_ce_fiber->default_object_handlers = &zend_fiber_handlers;
1110+
zend_ce_fiber->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
11101111

11111112
zend_fiber_handlers = std_object_handlers;
11121113
zend_fiber_handlers.dtor_obj = zend_fiber_object_destroy;

Zend/zend_generators.c

+1
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,7 @@ void zend_register_generator_ce(void) /* {{{ */
12151215
/* get_iterator has to be assigned *after* implementing the interface */
12161216
zend_ce_generator->get_iterator = zend_generator_get_iterator;
12171217
zend_ce_generator->default_object_handlers = &zend_generator_handlers;
1218+
zend_ce_generator->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
12181219

12191220
memcpy(&zend_generator_handlers, &std_object_handlers, sizeof(zend_object_handlers));
12201221
zend_generator_handlers.free_obj = zend_generator_free_storage;

Zend/zend_inheritance.c

+4
Original file line numberDiff line numberDiff line change
@@ -1810,6 +1810,7 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
18101810
ce->parent = parent_ce;
18111811
ce->default_object_handlers = parent_ce->default_object_handlers;
18121812
ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1813+
ce->ce_flags |= (parent_ce->ce_flags & ZEND_ACC_MAY_BE_CYCLIC);
18131814

18141815
/* Inherit properties */
18151816
if (parent_ce->default_properties_count) {
@@ -2832,6 +2833,9 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent
28322833
if (!traits[i]) {
28332834
continue;
28342835
}
2836+
2837+
ce->ce_flags |= (traits[i]->ce_flags & ZEND_ACC_MAY_BE_CYCLIC);
2838+
28352839
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
28362840
uint32_t flags = property_info->flags;
28372841

Zend/zend_object_handlers.c

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ ZEND_API HashTable *rebuild_object_properties_internal(zend_object *zobj) /* {{{
7070
zend_class_entry *ce = zobj->ce;
7171
int i;
7272

73+
GC_TYPE_INFO(zobj) &= ~(GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT);
74+
7375
zobj->properties = zend_new_array(ce->default_properties_count);
7476
if (ce->default_properties_count) {
7577
zend_hash_real_init_mixed(zobj->properties);

Zend/zend_objects.c

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ static zend_always_inline void _zend_object_std_init(zend_object *object, zend_c
3131
{
3232
GC_SET_REFCOUNT(object, 1);
3333
GC_TYPE_INFO(object) = GC_OBJECT;
34+
if (!(ce->ce_flags & ZEND_ACC_MAY_BE_CYCLIC)) {
35+
GC_TYPE_INFO(object) |= (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT);
36+
}
3437
object->ce = ce;
3538
object->extra_flags = 0;
3639
object->handlers = ce->default_object_handlers;

Zend/zend_weakrefs.c

+1
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ void zend_register_weakref_ce(void) /* {{{ */
788788
zend_ce_weakmap->create_object = zend_weakmap_create_object;
789789
zend_ce_weakmap->get_iterator = zend_weakmap_get_iterator;
790790
zend_ce_weakmap->default_object_handlers = &zend_weakmap_handlers;
791+
zend_ce_weakmap->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
791792

792793
memcpy(&zend_weakmap_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
793794
zend_weakmap_handlers.offset = XtOffsetOf(zend_weakmap, std);

ext/curl/interface.c

+1
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ PHP_MINIT_FUNCTION(curl)
395395
curl_ce = register_class_CurlHandle();
396396
curl_ce->create_object = curl_create_object;
397397
curl_ce->default_object_handlers = &curl_object_handlers;
398+
curl_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
398399

399400
memcpy(&curl_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
400401
curl_object_handlers.offset = XtOffsetOf(php_curl, std);

ext/curl/multi.c

+1
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ static zend_object_handlers curl_multi_handlers;
606606
void curl_multi_register_handlers(void) {
607607
curl_multi_ce->create_object = curl_multi_create_object;
608608
curl_multi_ce->default_object_handlers = &curl_multi_handlers;
609+
curl_multi_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
609610

610611
memcpy(&curl_multi_handlers, &std_object_handlers, sizeof(zend_object_handlers));
611612
curl_multi_handlers.offset = XtOffsetOf(php_curlm, std);

ext/dom/php_dom.c

+2
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,7 @@ PHP_MINIT_FUNCTION(dom)
12921292
dom_xpath_class_entry = register_class_DOMXPath();
12931293
dom_xpath_class_entry->create_object = dom_xpath_objects_new;
12941294
dom_xpath_class_entry->default_object_handlers = &dom_xpath_object_handlers;
1295+
dom_xpath_class_entry->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
12951296

12961297
zend_hash_init(&dom_xpath_prop_handlers, 0, NULL, NULL, true);
12971298
DOM_REGISTER_PROP_HANDLER(&dom_xpath_prop_handlers, "document", dom_xpath_document_read, NULL);
@@ -1301,6 +1302,7 @@ PHP_MINIT_FUNCTION(dom)
13011302
dom_modern_xpath_class_entry = register_class_Dom_XPath();
13021303
dom_modern_xpath_class_entry->create_object = dom_xpath_objects_new;
13031304
dom_modern_xpath_class_entry->default_object_handlers = &dom_xpath_object_handlers;
1305+
dom_modern_xpath_class_entry->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
13041306

13051307
zend_hash_add_new_ptr(&classes, dom_modern_xpath_class_entry->name, &dom_xpath_prop_handlers);
13061308
#endif

ext/pdo/pdo_dbh.c

+1
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,7 @@ void pdo_dbh_init(int module_number)
14491449
pdo_dbh_ce = register_class_PDO();
14501450
pdo_dbh_ce->create_object = pdo_dbh_new;
14511451
pdo_dbh_ce->default_object_handlers = &pdo_dbh_object_handlers;
1452+
pdo_dbh_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
14521453

14531454
memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
14541455
pdo_dbh_object_handlers.offset = XtOffsetOf(pdo_dbh_object_t, std);

ext/pdo/pdo_stmt.c

+1
Original file line numberDiff line numberDiff line change
@@ -2491,6 +2491,7 @@ void pdo_stmt_init(void)
24912491
pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
24922492
pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
24932493
pdo_dbstmt_ce->default_object_handlers = &pdo_dbstmt_object_handlers;
2494+
pdo_dbstmt_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
24942495

24952496
memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
24962497
pdo_dbstmt_object_handlers.offset = XtOffsetOf(pdo_stmt_t, std);

ext/reflection/php_reflection.c

+32
Original file line numberDiff line numberDiff line change
@@ -4343,6 +4343,16 @@ ZEND_METHOD(ReflectionClass, getAttributes)
43434343
}
43444344
/* }}} */
43454345

4346+
ZEND_METHOD(ReflectionClass, mayBeCyclic)
4347+
{
4348+
reflection_object *intern;
4349+
zend_class_entry *ce;
4350+
4351+
GET_REFLECTION_OBJECT_PTR(ce);
4352+
4353+
RETURN_BOOL(ce->ce_flags & ZEND_ACC_MAY_BE_CYCLIC);
4354+
}
4355+
43464356
/* {{{ Returns the class' constructor if there is one, NULL otherwise */
43474357
ZEND_METHOD(ReflectionClass, getConstructor)
43484358
{
@@ -7682,91 +7692,113 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
76827692

76837693
reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr);
76847694
reflection_function_abstract_ptr->default_object_handlers = &reflection_object_handlers;
7695+
reflection_function_abstract_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
76857696
reflection_function_abstract_ptr->create_object = reflection_objects_new;
76867697

76877698
reflection_function_ptr = register_class_ReflectionFunction(reflection_function_abstract_ptr);
76887699
reflection_function_ptr->create_object = reflection_objects_new;
76897700
reflection_function_ptr->default_object_handlers = &reflection_object_handlers;
7701+
reflection_function_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
76907702

76917703
reflection_generator_ptr = register_class_ReflectionGenerator();
76927704
reflection_generator_ptr->create_object = reflection_objects_new;
76937705
reflection_generator_ptr->default_object_handlers = &reflection_object_handlers;
7706+
reflection_generator_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
76947707

76957708
reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr);
76967709
reflection_parameter_ptr->create_object = reflection_objects_new;
76977710
reflection_parameter_ptr->default_object_handlers = &reflection_object_handlers;
7711+
reflection_parameter_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
76987712

76997713
reflection_type_ptr = register_class_ReflectionType(zend_ce_stringable);
77007714
reflection_type_ptr->create_object = reflection_objects_new;
77017715
reflection_type_ptr->default_object_handlers = &reflection_object_handlers;
7716+
reflection_type_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77027717

77037718
reflection_named_type_ptr = register_class_ReflectionNamedType(reflection_type_ptr);
77047719
reflection_named_type_ptr->create_object = reflection_objects_new;
77057720
reflection_named_type_ptr->default_object_handlers = &reflection_object_handlers;
7721+
reflection_named_type_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77067722

77077723
reflection_union_type_ptr = register_class_ReflectionUnionType(reflection_type_ptr);
77087724
reflection_union_type_ptr->create_object = reflection_objects_new;
77097725
reflection_union_type_ptr->default_object_handlers = &reflection_object_handlers;
7726+
reflection_union_type_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77107727

77117728
reflection_intersection_type_ptr = register_class_ReflectionIntersectionType(reflection_type_ptr);
77127729
reflection_intersection_type_ptr->create_object = reflection_objects_new;
77137730
reflection_intersection_type_ptr->default_object_handlers = &reflection_object_handlers;
7731+
reflection_intersection_type_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77147732

77157733
reflection_method_ptr = register_class_ReflectionMethod(reflection_function_abstract_ptr);
77167734
reflection_method_ptr->create_object = reflection_objects_new;
77177735
reflection_method_ptr->default_object_handlers = &reflection_object_handlers;
7736+
reflection_method_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77187737

77197738
reflection_class_ptr = register_class_ReflectionClass(reflector_ptr);
77207739
reflection_class_ptr->create_object = reflection_objects_new;
77217740
reflection_class_ptr->default_object_handlers = &reflection_object_handlers;
7741+
reflection_class_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77227742

77237743
reflection_object_ptr = register_class_ReflectionObject(reflection_class_ptr);
77247744
reflection_object_ptr->create_object = reflection_objects_new;
77257745
reflection_object_ptr->default_object_handlers = &reflection_object_handlers;
7746+
reflection_object_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77267747

77277748
reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr);
77287749
reflection_property_ptr->create_object = reflection_objects_new;
77297750
reflection_property_ptr->default_object_handlers = &reflection_object_handlers;
7751+
reflection_property_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77307752

77317753
reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr);
77327754
reflection_class_constant_ptr->create_object = reflection_objects_new;
77337755
reflection_class_constant_ptr->default_object_handlers = &reflection_object_handlers;
7756+
reflection_class_constant_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77347757

77357758
reflection_extension_ptr = register_class_ReflectionExtension(reflector_ptr);
77367759
reflection_extension_ptr->create_object = reflection_objects_new;
77377760
reflection_extension_ptr->default_object_handlers = &reflection_object_handlers;
7761+
reflection_extension_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77387762

77397763
reflection_zend_extension_ptr = register_class_ReflectionZendExtension(reflector_ptr);
77407764
reflection_zend_extension_ptr->create_object = reflection_objects_new;
77417765
reflection_zend_extension_ptr->default_object_handlers = &reflection_object_handlers;
7766+
reflection_zend_extension_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77427767

77437768
reflection_reference_ptr = register_class_ReflectionReference();
77447769
reflection_reference_ptr->create_object = reflection_objects_new;
77457770
reflection_reference_ptr->default_object_handlers = &reflection_object_handlers;
7771+
reflection_reference_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77467772

77477773
reflection_attribute_ptr = register_class_ReflectionAttribute(reflector_ptr);
77487774
reflection_attribute_ptr->create_object = reflection_objects_new;
77497775
reflection_attribute_ptr->default_object_handlers = &reflection_object_handlers;
7776+
reflection_attribute_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77507777

77517778
reflection_enum_ptr = register_class_ReflectionEnum(reflection_class_ptr);
77527779
reflection_enum_ptr->create_object = reflection_objects_new;
77537780
reflection_enum_ptr->default_object_handlers = &reflection_object_handlers;
7781+
reflection_enum_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77547782

77557783
reflection_enum_unit_case_ptr = register_class_ReflectionEnumUnitCase(reflection_class_constant_ptr);
77567784
reflection_enum_unit_case_ptr->create_object = reflection_objects_new;
77577785
reflection_enum_unit_case_ptr->default_object_handlers = &reflection_object_handlers;
7786+
reflection_enum_unit_case_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77587787

77597788
reflection_enum_backed_case_ptr = register_class_ReflectionEnumBackedCase(reflection_enum_unit_case_ptr);
77607789
reflection_enum_backed_case_ptr->create_object = reflection_objects_new;
77617790
reflection_enum_backed_case_ptr->default_object_handlers = &reflection_object_handlers;
7791+
reflection_enum_backed_case_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77627792

77637793
reflection_fiber_ptr = register_class_ReflectionFiber();
77647794
reflection_fiber_ptr->create_object = reflection_objects_new;
77657795
reflection_fiber_ptr->default_object_handlers = &reflection_object_handlers;
7796+
reflection_fiber_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77667797

77677798
reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr);
77687799
reflection_constant_ptr->create_object = reflection_objects_new;
77697800
reflection_constant_ptr->default_object_handlers = &reflection_object_handlers;
7801+
reflection_constant_ptr->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
77707802

77717803
reflection_property_hook_type_ptr = register_class_PropertyHookType();
77727804

ext/reflection/php_reflection.stub.php

+2
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,8 @@ public function getNamespaceName(): string {}
432432
public function getShortName(): string {}
433433

434434
public function getAttributes(?string $name = null, int $flags = 0): array {}
435+
436+
public function mayBeCyclic(): bool {}
435437
}
436438

437439
class ReflectionObject extends ReflectionClass

ext/reflection/php_reflection_arginfo.h

+5-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/simplexml/simplexml.c

+1
Original file line numberDiff line numberDiff line change
@@ -2654,6 +2654,7 @@ PHP_MINIT_FUNCTION(simplexml)
26542654
ce_SimpleXMLElement = register_class_SimpleXMLElement(zend_ce_stringable, zend_ce_countable, spl_ce_RecursiveIterator);
26552655
ce_SimpleXMLElement->create_object = sxe_object_new;
26562656
ce_SimpleXMLElement->default_object_handlers = &sxe_object_handlers;
2657+
ce_SimpleXMLElement->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
26572658
ce_SimpleXMLElement->get_iterator = php_sxe_get_iterator;
26582659

26592660
memcpy(&sxe_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));

ext/sockets/sockets.c

+1
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ static PHP_MINIT_FUNCTION(sockets)
455455
socket_ce = register_class_Socket();
456456
socket_ce->create_object = socket_create_object;
457457
socket_ce->default_object_handlers = &socket_object_handlers;
458+
socket_ce->ce_flags |= ZEND_ACC_MAY_BE_CYCLIC;
458459

459460
memcpy(&socket_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
460461
socket_object_handlers.offset = XtOffsetOf(php_socket, std);

0 commit comments

Comments
 (0)