--- /dev/null
+--TEST--
+Ensure object comparison property order remains consistent
+--FILE--
+<?php
+
+// PHP4-5.3 object semantics had child properties added to an
+// object HashTable first, then parent, then grandparent, etc...
+// As of PHP 5.4 we use a packed C array to hold properties
+// which may or may not share the same ordering.
+// In the code snippet below, the print_r() has the side-effect
+// of materializing the properties shadow HashTable which
+// if used for comparison, results in the behavior consistent
+// with pre PHP-5.4.
+// This test ensures that the first comparison yields the same
+// result without shadow table materialization.
+
+class A { public $a; }
+class B extends A { public $b; }
+$a = new B(); $a->a = 0; $a->b = 1;
+$b = new B(); $b->a = 1; $b->b = 0;
+
+var_dump($a < $b);
+print_r($a, true);
+var_dump($a < $b);
+--EXPECT--
+bool(false)
+bool(false)
return 1; /* different classes */
}
if (!zobj1->properties && !zobj2->properties) {
- zval *p1, *p2, *end;
+ zend_property_info *info;
if (!zobj1->ce->default_properties_count) {
return 0;
}
- p1 = zobj1->properties_table;
- p2 = zobj2->properties_table;
- end = p1 + zobj1->ce->default_properties_count;
/* It's enough to protect only one of the objects.
* The second one may be referenced from the first and this may cause
zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");
}
Z_PROTECT_RECURSION_P(o1);
- do {
+
+ ZEND_HASH_FOREACH_PTR(&zobj1->ce->properties_info, info) {
+ zval *p1 = OBJ_PROP(zobj1, info->offset);
+ zval *p2 = OBJ_PROP(zobj2, info->offset);
+
+ if (info->flags & ZEND_ACC_STATIC) {
+ continue;
+ }
+
if (Z_TYPE_P(p1) != IS_UNDEF) {
if (Z_TYPE_P(p2) != IS_UNDEF) {
zval result;
return 1;
}
}
- p1++;
- p2++;
- } while (p1 != end);
+ } ZEND_HASH_FOREACH_END();
+
Z_UNPROTECT_RECURSION_P(o1);
return 0;
} else {