Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Adding and removing properties of classes (in PHP 5.4) whose objects …

…have dynamic properties have been corrected. Issues related to memory management have been eliminated. New tests were added. (#40)
  • Loading branch information...
commit cbcfa9b52d186f37db40d8f3f573f8f21ac6817a 1 parent a78fa7a
@zenovich authored
View
6 package.xml
@@ -37,6 +37,7 @@ Execute code in restricted environment (sandboxing).
+ Adding and redefining functions and methods, which return references, were fully implemented
New optional argument 'return_ref' of functions runkit_function_add and runkit_function_redefine was introduced
New constant RUNKIT_ACC_RETURN_REFERENCE was introduced for use with functions runkit_method_add and runkit_method_redefine
+ + Properties adding, removing, and importing were reworked for proper inheritance (including objects in PHP5+)
Critical fixes:
* Highly probable crashes on using Reflection objects after modifying removing or renaming of functions, methods, and properties,
@@ -53,12 +54,11 @@ Execute code in restricted environment (sandboxing).
* Adding of non-lowercase default properties was fixed (removed lowercasing)
* Skip the leading slash in class names
* Copying of functions was reworked
- * Properties adding, removing and importing were corrected for right inheritance
* Converting of input parameters (class names & function names) to lowecase was eliminated
* runkit_method_redefine function now sets the 'prototype' field for the method
and its descendants (Thanks to Anthony Dovgal)
* Freeing already freed memory on importing of a non-existent file was eliminated
- * Test for correctness of runkit.superglobals feature was added
+ * A test for correctness of runkit.superglobals feature was added
* Tests for correctness of inheritance of properties were added
* Tests for correctness of adding static properties were added
@@ -186,8 +186,10 @@ Execute code in restricted environment (sandboxing).
<file name="namespaces.phpt" role="test" />
<file name="runkit_default_property_add.phpt" role="test" />
<file name="runkit_default_property_add4.phpt" role="test" />
+ <file name="runkit_default_property_add_and_remove_for_class_with_dynamic_properties.phpt" role="test" />
<file name="runkit_default_property_add_to_subclasses.phpt" role="test" />
<file name="runkit_default_property_remove.phpt" role="test" />
+ <file name="runkit_default_property_remove_and_add_for_class_with_dynamic_properties.phpt" role="test" />
<file name="runkit_default_property_remove_and_reflection.phpt" role="test" />
<file name="runkit_default_property_remove_from_subclasses.phpt" role="test" />
<file name="runkit_default_property_remove_from_subclasses4.phpt" role="test" />
View
3  php_runkit.h
@@ -271,7 +271,8 @@ int php_runkit_update_children_consts(RUNKIT_53_TSRMLS_ARG(void *pDest), int num
/* runkit_props.c */
int php_runkit_update_children_def_props(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce), int num_args, va_list args, zend_hash_key *hash_key);
int php_runkit_def_prop_add_int(zend_class_entry *ce, const char *propname, int propname_len, zval *copyval, long visibility, const char *doc_comment, int doc_comment_len, zend_class_entry *definer_class, int override TSRMLS_DC);
-int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, int propname_len, zend_class_entry *definer_class TSRMLS_DC);
+int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, int propname_len, zend_class_entry *definer_class,
+ int parent_offset, zend_bool was_static TSRMLS_DC);
#ifdef ZEND_ENGINE_2
void php_runkit_remove_property_from_reflection_objects(zend_class_entry *ce, const char *prop_name, int prop_name_len TSRMLS_DC);
#endif
View
4 runkit_import.c
@@ -293,7 +293,7 @@ static int php_runkit_import_class_static_props(zend_class_entry *dce, zend_clas
if (zend_hash_find(&dce->properties_info, key, key_len, (void*) &ex_property_info_ptr) == SUCCESS && ex_property_info_ptr) {
if (override) {
if (!(ex_property_info_ptr->flags & ZEND_ACC_STATIC)) {
- if (php_runkit_def_prop_remove_int(dce, key, key_len - 1, NULL TSRMLS_CC) != SUCCESS) {
+ if (php_runkit_def_prop_remove_int(dce, key, key_len - 1, NULL, -1, 0 TSRMLS_CC) != SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to import %s::$%s (cannot remove old member)", dce->name, key);
goto import_st_prop_skip;
}
@@ -377,7 +377,7 @@ static int php_runkit_import_class_props(zend_class_entry *dce, zend_class_entry
if (override) {
if (php_runkit_def_prop_remove_int(dce, property_info_ptr->name,
property_info_ptr->name_length,
- NULL TSRMLS_CC) != SUCCESS) {
+ NULL, -1, 0 TSRMLS_CC) != SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Unable to remove old property %s%s%s, not importing",
dce->name, (property_info_ptr->flags & ZEND_ACC_STATIC) ? "::$" : "->",
View
128 runkit_props.c
@@ -59,6 +59,8 @@ int php_runkit_remove_children_def_props(RUNKIT_53_TSRMLS_ARG(zend_class_entry *
char *pname = va_arg(args, char*);
int pname_len = va_arg(args, int);
zend_class_entry *definer_class = va_arg(args, zend_class_entry*);
+ int parent_offset = va_arg(args, int);
+ zend_bool was_static = va_arg(args, int);
RUNKIT_UNDER53_TSRMLS_FETCH();
@@ -71,21 +73,23 @@ int php_runkit_remove_children_def_props(RUNKIT_53_TSRMLS_ARG(zend_class_entry *
return ZEND_HASH_APPLY_KEEP;
}
- php_runkit_def_prop_remove_int(ce, pname, pname_len, definer_class TSRMLS_CC);
+ php_runkit_def_prop_remove_int(ce, pname, pname_len, definer_class, parent_offset, was_static TSRMLS_CC);
return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
-/* {{{ php_runkit_remove_private_property_from_childs
+/* {{{ php_runkit_remove_shadowed_property_from_childs
Clean private properties by offset */
-int php_runkit_remove_private_property_from_childs(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce), int num_args, va_list args, zend_hash_key *hash_key)
+int php_runkit_remove_shadowed_property_from_childs(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce), int num_args, va_list args, zend_hash_key *hash_key)
{
zend_class_entry *parent_class = va_arg(args, zend_class_entry*);
char *pname = va_arg(args, char*);
int pname_len = va_arg(args, int);
int offset = va_arg(args, int);
+ zend_bool is_static = va_arg(args, int);
int i;
+ zval **table;
ce = *((zend_class_entry**)ce);
@@ -94,15 +98,17 @@ int php_runkit_remove_private_property_from_childs(RUNKIT_53_TSRMLS_ARG(zend_cla
return ZEND_HASH_APPLY_KEEP;
}
- if (ce->default_properties_table[offset]) {
- zval_ptr_dtor(&ce->default_properties_table[offset]);
- ce->default_properties_table[offset] = NULL;
+ table = is_static ? ce->default_static_members_table : ce->default_properties_table;
+ if (table[offset]) {
+ zval_ptr_dtor(&table[offset]);
+ table[offset] = NULL;
}
- zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_remove_private_property_from_childs,
- 4, ce, pname, pname_len, offset);
+
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_remove_shadowed_property_from_childs,
+ 5, ce, pname, pname_len, offset, is_static);
php_runkit_remove_property_from_reflection_objects(ce, pname, pname_len TSRMLS_CC);
- if (!EG(objects_store).object_buckets) {
+ if (is_static || !EG(objects_store).object_buckets) {
return ZEND_HASH_APPLY_KEEP;
}
for (i = 1; i < EG(objects_store).top ; i++) {
@@ -111,11 +117,13 @@ int php_runkit_remove_private_property_from_childs(RUNKIT_53_TSRMLS_ARG(zend_cla
zend_object *object;
object = (zend_object *) EG(objects_store).object_buckets[i].bucket.obj.object;
if (object->ce == ce) {
- if (object->properties_table) {
- if (object->properties_table[offset]) {
+ if (object->properties_table[offset]) {
+ if (!object->properties) {
zval_ptr_dtor(&object->properties_table[offset]);
- object->properties_table[offset] = NULL;
+ } else {
+ zend_hash_del(object->properties, pname, pname_len+1);
}
+ object->properties_table[offset] = NULL;
}
}
}
@@ -133,17 +141,20 @@ int php_runkit_def_prop_add_int(zend_class_entry *ce, const char *propname, int
#if PHP_MAJOR_VERSION >= 5
int i;
#endif
+#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
+ int offset;
+#endif
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 3
HashTable *symt;
#endif
#if PHP_MAJOR_VERSION >= 5
- zend_property_info *prop_info_ptr;
+ zend_property_info *prop_info_ptr = NULL;
long h = zend_get_hash_value((char *) propname, propname_len + 1);
#endif
zval *pcopyval = copyval;
#if PHP_MAJOR_VERSION >= 5
- if ((visibility & ZEND_ACC_PRIVATE) && (visibility & ZEND_ACC_STATIC) && definer_class && definer_class != ce) {
+ if ((visibility & ZEND_ACC_PRIVATE) && (visibility & ZEND_ACC_STATIC) && definer_class && definer_class != ce) {
return SUCCESS;
}
@@ -171,9 +182,13 @@ int php_runkit_def_prop_add_int(zend_class_entry *ce, const char *propname, int
ce->name, (prop_info_ptr->flags & ZEND_ACC_STATIC) ? "::$" : "->", propname);
return FAILURE;
} else {
- php_runkit_def_prop_remove_int(ce, propname, propname_len, NULL TSRMLS_CC);
+ php_runkit_def_prop_remove_int(ce, propname, propname_len, NULL, -1, 0 TSRMLS_CC);
+#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
+ php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
+#endif
}
}
+ prop_info_ptr = NULL;
#else
if (zend_hash_exists(&ce->default_properties, (char *) propname, propname_len + 1)) {
if (override) {
@@ -248,6 +263,15 @@ int php_runkit_def_prop_add_int(zend_class_entry *ce, const char *propname, int
propname, propname_len, visibility, definer_class, override);
#if PHP_MAJOR_VERSION >= 5
+ if (!prop_info_ptr && zend_hash_quick_find(&ce->properties_info, (char *) propname, propname_len + 1, h, (void*) &prop_info_ptr) != SUCCESS) {
+ zval_ptr_dtor(&pcopyval);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot find just added property's info");
+ return FAILURE;
+ }
+#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
+ offset = prop_info_ptr->offset;
+#endif
+
if ((visibility & ZEND_ACC_STATIC) || !EG(objects_store).object_buckets) {
return SUCCESS;
}
@@ -259,13 +283,18 @@ int php_runkit_def_prop_add_int(zend_class_entry *ce, const char *propname, int
if (object->ce == ce) {
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
if (!object->properties_table) {
- object->properties_table = pemalloc(sizeof(void*) * ce->default_properties_count, 0);
+ object->properties_table = pemalloc(sizeof(void*) * (offset + 1), 0);
} else {
- object->properties_table = perealloc(object->properties_table, sizeof(void*) * ce->default_properties_count, 0);
+ object->properties_table = perealloc(object->properties_table, sizeof(void*) * (offset + 1), 0);
}
- object->properties_table[ce->default_properties_count-1] = ce->default_properties_table[ce->default_properties_count-1];
- if (object->properties_table[ce->default_properties_count-1]) {
- Z_ADDREF_P(object->properties_table[ce->default_properties_count-1]);
+
+ if (ce->default_properties_table[offset]) {
+ if (!object->properties) {
+ object->properties_table[offset] = ce->default_properties_table[offset];
+ } else {
+ zend_hash_quick_update(object->properties, propname, propname_len+1, h, &ce->default_properties_table[offset], sizeof(zval *), (void**)&object->properties_table[offset]);
+ }
+ Z_ADDREF_P(ce->default_properties_table[offset]);
}
#else
if (!object->properties) {
@@ -273,8 +302,8 @@ int php_runkit_def_prop_add_int(zend_class_entry *ce, const char *propname, int
zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
}
Z_ADDREF_P(pcopyval);
- zend_hash_quick_del(object->properties, (char *) propname, propname_len + 1, h);
- zend_hash_quick_add(object->properties, (char *) propname, propname_len + 1, h, &pcopyval, sizeof(zval *), NULL);
+ zend_hash_quick_del(object->properties, (char *) prop_info_ptr->name, prop_info_ptr->name_length + 1, prop_info_ptr->h);
+ zend_hash_quick_add(object->properties, (char *) prop_info_ptr->name, prop_info_ptr->name_length + 1, prop_info_ptr->h, &pcopyval, sizeof(zval *), NULL);
#endif // (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
}
}
@@ -341,7 +370,8 @@ static int php_runkit_def_prop_add(char *classname, int classname_len, char *pro
/* }}} */
/* {{{ php_runkit_def_prop_remove */
-int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, int propname_len, zend_class_entry *definer_class TSRMLS_DC)
+int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, int propname_len, zend_class_entry *definer_class,
+ int parent_offset, zend_bool was_static TSRMLS_DC)
{
#if PHP_MAJOR_VERSION == 4
/* Resolve the property's name */
@@ -353,13 +383,14 @@ int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, i
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to remove the property from class: %s::%s", ce->name, propname);
return FAILURE;
}
- zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t)php_runkit_remove_children_def_props, 4, ce, propname, propname_len, NULL);
+ zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t)php_runkit_remove_children_def_props, 6, ce, propname, propname_len, -1, 0, NULL);
#else
int i;
long h;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
int offset;
#endif
+ int flags;
zend_property_info *property_info_ptr;
h = zend_get_hash_value((char *) propname, propname_len + 1);
@@ -378,13 +409,20 @@ int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, i
}
efree(private);
zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_remove_children_def_props,
- 4, ce, propname, propname_len, definer_class);
+ 6, ce, propname, propname_len, definer_class, -1, 0);
+#elif (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
+ if (parent_offset >= 0 && parent_offset != property_info_ptr->offset) {
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)),
+ (apply_func_args_t)php_runkit_remove_shadowed_property_from_childs,
+ 5, ce, propname, propname_len, parent_offset, was_static);
+ }
#endif // PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4
return SUCCESS;
} else if (!definer_class) {
definer_class = property_info_ptr->ce;
}
if (property_info_ptr->flags & ZEND_ACC_STATIC) {
+ was_static = 1;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
if (ce->default_static_members_table[property_info_ptr->offset]) {
zval_ptr_dtor(&ce->default_static_members_table[property_info_ptr->offset]);
@@ -398,6 +436,7 @@ int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, i
}
#endif // (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
} else {
+ was_static = 0;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
if (ce->default_properties_table[property_info_ptr->offset]) {
zval_ptr_dtor(&ce->default_properties_table[property_info_ptr->offset]);
@@ -412,27 +451,41 @@ int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, i
#endif // (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
}
+ flags = property_info_ptr->flags;
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
offset = property_info_ptr->offset;
- if ((property_info_ptr->flags & ZEND_ACC_PRIVATE) && !(property_info_ptr->flags & ZEND_ACC_STATIC) && offset >= 0) {
- zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_remove_private_property_from_childs,
- 4, ce, propname, propname_len, offset);
- } else
+
+ if (property_info_ptr->flags & ZEND_ACC_PRIVATE) {
+ if (offset >= 0) {
+ zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)),
+ (apply_func_args_t)php_runkit_remove_shadowed_property_from_childs,
+ 5, ce, propname, propname_len, offset, property_info_ptr->flags & ZEND_ACC_STATIC);
+ }
+ }
#endif
zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_remove_children_def_props,
- 4, ce, propname, propname_len, definer_class);
+ 6, ce, propname, propname_len, definer_class,
+#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
+ offset, was_static
+#else
+ -1, 0
+#endif
+ );
php_runkit_remove_property_from_reflection_objects(ce, propname, propname_len TSRMLS_CC);
if (zend_hash_quick_del(&ce->properties_info, (char *) propname, propname_len + 1, h) != SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to remove the property %s::%s", ce->name, propname);
return FAILURE;
}
+#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
+ php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
+#endif
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::%s does not exist", ce->name, propname);
return FAILURE;
}
- if (!EG(objects_store).object_buckets) {
+ if ((flags & ZEND_ACC_STATIC) || !EG(objects_store).object_buckets) {
return SUCCESS;
}
for (i = 1; i < EG(objects_store).top ; i++) {
@@ -442,11 +495,13 @@ int php_runkit_def_prop_remove_int(zend_class_entry *ce, const char *propname, i
object = (zend_object *) EG(objects_store).object_buckets[i].bucket.obj.object;
if (object->ce == ce) {
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
- if (object->properties_table) {
- if (object->properties_table[offset]) {
+ if (object->properties_table[offset]) {
+ if (!object->properties) {
zval_ptr_dtor(&object->properties_table[offset]);
- object->properties_table[offset] = NULL;
+ } else {
+ zend_hash_quick_del(object->properties, propname, propname_len+1, h);
}
+ object->properties_table[offset] = NULL;
}
#else
if (object->properties) {
@@ -476,7 +531,10 @@ static int php_runkit_def_prop_remove(char *classname, int classname_len, char *
return FAILURE;
}
- return php_runkit_def_prop_remove_int(ce, propname, propname_len, NULL TSRMLS_CC);
+#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) || (PHP_MAJOR_VERSION > 5)
+ php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
+#endif
+ return php_runkit_def_prop_remove_int(ce, propname, propname_len, NULL, -1, 0 TSRMLS_CC);
}
/* }}} */
View
56 tests/runkit_default_property_add_and_remove_for_class_with_dynamic_properties.phpt
@@ -0,0 +1,56 @@
+--TEST--
+runkit_default_property_add() and runkit_default_property_remove() functions on classes having dynamic properties
+--SKIPIF--
+<?php if(!extension_loaded("runkit") || !RUNKIT_FEATURE_MANIPULATION) print "skip";
+ if(array_shift(explode('.', PHP_VERSION)) < 5) print "skip";
+?>
+--FILE--
+<?php
+class A {
+ var $d=3;
+}
+
+class B extends A {
+}
+
+$o = new A;
+$o->b = 1;
+echo 'b=', $o->b, "\n";
+echo 'd=', $o->d, "\n";
+runkit_default_property_add('A', 'b', 2);
+echo 'b=', $o->b, "\n";
+echo 'd=', $o->d, "\n";
+runkit_default_property_remove('A', 'b');
+echo 'b=', @$o->b, "\n";
+echo 'd=', $o->d, "\n";
+
+echo "\n";
+
+$o = new B;
+echo 'b=', @$o->b, "\n";
+echo 'd=', $o->d, "\n";
+$o->b = 1;
+echo 'b=', $o->b, "\n";
+echo 'd=', $o->d, "\n";
+runkit_default_property_add('A', 'b', 2);
+echo 'b=', $o->b, "\n";
+echo 'd=', $o->d, "\n";
+runkit_default_property_remove('A', 'b');
+echo 'b=', @$o->b, "\n";
+echo 'd=', $o->d, "\n";
+--EXPECT--
+b=1
+d=3
+b=2
+d=3
+b=
+d=3
+
+b=
+d=3
+b=1
+d=3
+b=2
+d=3
+b=
+d=3
View
76 tests/runkit_default_property_remove_and_add_for_class_with_dynamic_properties.phpt
@@ -0,0 +1,76 @@
+--TEST--
+runkit_default_property_remove() and runkit_default_property_add() functions on classes having dynamic properties
+--SKIPIF--
+<?php if(!extension_loaded("runkit") || !RUNKIT_FEATURE_MANIPULATION) print "skip";
+ if(array_shift(explode('.', PHP_VERSION)) < 5) print "skip";
+?>
+--FILE--
+<?php
+class A {
+ private $c = 1;
+ public $d = 'd';
+ public function getC() {return $this->c;}
+}
+class B extends A {}
+
+$o = new B;
+echo $o->getC(), "\n";
+echo $o->b, $o->d, "\n";
+$o->b = 'b';
+echo $o->getC(), "\n";
+echo $o->b, $o->d, "\n";
+echo "remove\n";
+runkit_default_property_remove('A', 'c');
+echo $o->getC(), "\n";
+echo $o->b, $o->d, "\n";
+echo "add public\n";
+runkit_default_property_add('A', 'c', 2);
+echo $o->getC(), "\n";
+echo $o->b, $o->d, "\n";
+echo "remove\n";
+runkit_default_property_remove('A', 'c');
+echo $o->getC(), "\n";
+echo $o->b, $o->d, "\n";
+echo "add private\n";
+runkit_default_property_add('A', 'c', 3, RUNKIT_ACC_PRIVATE);
+echo $o->getC(), "\n";
+echo $o->b, $o->d, "\n";
+echo "remove\n";
+runkit_default_property_remove('A', 'c');
+echo $o->getC(), "\n";
+echo $o->b, $o->d, "\n";
+echo "add public to B\n";
+runkit_default_property_add('B', 'c', 2);
+echo $o->getC(), "\n";
+echo $o->b, $o->d, "\n";
+--EXPECTF--
+1
+
+Notice: Undefined property: B::$b in %s on line %d
+d
+1
+bd
+remove
+
+Notice: Undefined property: B::$c in %s on line %d
+
+bd
+add public
+2
+bd
+remove
+
+Notice: Undefined property: B::$c in %s on line %d
+
+bd
+add private
+3
+bd
+remove
+
+Notice: Undefined property: B::$c in %s on line %d
+
+bd
+add public to B
+2
+bd
Please sign in to comment.
Something went wrong with that request. Please try again.