]> granicus.if.org Git - php/commitdiff
Make DateInterval objects uncomparable
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 18 Apr 2019 11:46:10 +0000 (13:46 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 23 Apr 2019 11:12:06 +0000 (13:12 +0200)
Arbitrary DateInterval objects don't have well-defined comparison
semantics. Throw a warning and treat the objects as uncomparable.

Support for comparing DateInterval objects returned by
DateTime::diff() may be added in the future.

UPGRADING
ext/date/php_date.c
ext/date/tests/bug70810.phpt [new file with mode: 0644]
ext/date/tests/bug74639.phpt

index 9768e5f7e41c0e4f6cd5dff4c9c7cfdb20390514..0bcdae197143563be5a09bfbd9abe380971f68df 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -32,6 +32,9 @@ PHP 7.4 UPGRADE NOTES
 - Date:
   . Calling var_dump() or similar on a DateTime(Immutable) instance will no
     longer leave behind accessible properties on the object.
+  . Comparison of DateInterval objects (using ==, < and so on) will now generate
+    a warning and always return false. Previously all DateInterval objects were
+    considered equal, unless they had properties.
 
 - Intl:
   . The default parameter value of idn_to_ascii() and idn_to_utf8() is now
index 03fdc18284a785e673abe73eb76dfaa4c28ab2c9..4d0a20df9743c87b234708f0bd2ffc0c3d2a5a7a 100644 (file)
@@ -656,8 +656,9 @@ static HashTable *date_object_get_gc_timezone(zval *object, zval **table, int *n
 static HashTable *date_object_get_debug_info_timezone(zval *object, int *is_temp);
 static void php_timezone_to_string(php_timezone_obj *tzobj, zval *zv);
 
-zval *date_interval_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv);
-zval *date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot);
+static int date_interval_compare_objects(zval *o1, zval *o2);
+static zval *date_interval_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv);
+static zval *date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot);
 static zval *date_interval_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot);
 static zval *date_period_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv);
 static zval *date_period_write_property(zval *object, zval *member, zval *value, void **cache_slot);
@@ -2164,6 +2165,7 @@ static void date_register_classes(void) /* {{{ */
        date_object_handlers_interval.get_properties = date_object_get_properties_interval;
        date_object_handlers_interval.get_property_ptr_ptr = date_interval_get_property_ptr_ptr;
        date_object_handlers_interval.get_gc = date_object_get_gc_interval;
+       date_object_handlers_interval.compare_objects = date_interval_compare_objects;
 
        INIT_CLASS_ENTRY(ce_period, "DatePeriod", date_funcs_period);
        ce_period.create_object = date_object_new_period;
@@ -4142,8 +4144,16 @@ static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *forma
        return retval;
 } /* }}} */
 
+static int date_interval_compare_objects(zval *o1, zval *o2) {
+       /* There is no well defined way to compare intervals like P1M and P30D, which may compare
+        * smaller, equal or greater depending on the point in time at which the interval starts. As
+        * such, we treat DateInterval objects are non-comparable and emit a warning. */
+       zend_error(E_WARNING, "Cannot compare DateInterval objects");
+       return 1;
+}
+
 /* {{{ date_interval_read_property */
-zval *date_interval_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv)
+static zval *date_interval_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv)
 {
        php_interval_obj *obj;
        zval *retval;
@@ -4214,7 +4224,7 @@ zval *date_interval_read_property(zval *object, zval *member, int type, void **c
 /* }}} */
 
 /* {{{ date_interval_write_property */
-zval *date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot)
+static zval *date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot)
 {
        php_interval_obj *obj;
        zval tmp_member;
diff --git a/ext/date/tests/bug70810.phpt b/ext/date/tests/bug70810.phpt
new file mode 100644 (file)
index 0000000..1918e56
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+Bug #70810: DateInterval equals every other DateInterval
+--FILE--
+<?php
+
+$i1 = new DateInterval('P1D');
+$i2 = new DateInterval('PT1H');
+var_dump($i1 == $i2);
+var_dump($i1 < $i2);
+var_dump($i1 > $i2);
+
+$i2 = new DateInterval('P1D');
+var_dump($i1 == $i2);
+var_dump($i1 < $i2);
+var_dump($i1 > $i2);
+
+?>
+--EXPECTF--
+Warning: Cannot compare DateInterval objects in %s on line %d
+bool(false)
+
+Warning: Cannot compare DateInterval objects in %s on line %d
+bool(false)
+
+Warning: Cannot compare DateInterval objects in %s on line %d
+bool(false)
+
+Warning: Cannot compare DateInterval objects in %s on line %d
+bool(false)
+
+Warning: Cannot compare DateInterval objects in %s on line %d
+bool(false)
+
+Warning: Cannot compare DateInterval objects in %s on line %d
+bool(false)
index 43eccc974dc1b7fe0ecb000e80a64b6b9df9643f..7a9c31e5304a3a4d1e43d73f872656a4cf53d96b 100644 (file)
@@ -19,10 +19,6 @@ if ($period->getEndDate() != $clonedPeriod->getEndDate()) {
     echo "failure\n";
 }
 
-if ($period->getDateInterval() != $clonedPeriod->getDateInterval()) {
-    echo "failure\n";
-}
-
 if ($interval->format('Y-m-d H:i:s') != $clonedInterval->format('Y-m-d H:i:s')) {
     echo "failure\n";
 }