Skip to content

Commit 3b2f2ce

Browse files
committed
Make uninitialized DateTime an Error
This avoids many spurious false return values.
1 parent 33886f7 commit 3b2f2ce

File tree

8 files changed

+106
-92
lines changed

8 files changed

+106
-92
lines changed

ext/date/php_date.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,8 @@ static zend_object_handlers date_object_handlers_period;
303303

304304
#define DATE_CHECK_INITIALIZED(member, class_name) \
305305
if (!(member)) { \
306-
php_error_docref(NULL, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
307-
RETURN_FALSE; \
306+
zend_throw_error(NULL, "The " #class_name " object has not been correctly initialized by its constructor"); \
307+
return; \
308308
}
309309

310310
static void date_object_free_storage_date(zend_object *object);

ext/date/php_date.stub.php

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -57,57 +57,46 @@ function date_parse_from_format(string $format, string $date): array {}
5757
/** @return array|false */
5858
function date_get_last_errors() {}
5959

60-
/** @return string|false */
61-
function date_format(DateTimeInterface $object, string $format) {}
60+
function date_format(DateTimeInterface $object, string $format): string {}
6261

6362
/** @return DateTime|false */
6463
function date_modify(DateTime $object, string $modify) {}
6564

66-
/** @return DateTime|false */
67-
function date_add(DateTime $object, DateInterval $interval) {}
65+
function date_add(DateTime $object, DateInterval $interval): DateTime {}
6866

69-
/** @return DateTime|false */
70-
function date_sub(DateTime $object, DateInterval $interval) {}
67+
function date_sub(DateTime $object, DateInterval $interval): DateTime {}
7168

7269
/** @return DateTimeZone|false */
7370
function date_timezone_get(DateTimeInterface $object) {}
7471

75-
/** @return DateTime|false */
76-
function date_timezone_set(DateTimeInterface $object, DateTimeZone $timezone) {}
72+
function date_timezone_set(DateTimeInterface $object, DateTimeZone $timezone): DateTime {}
7773

78-
/** @return int|false */
79-
function date_offset_get(DateTimeInterface $object) {}
74+
function date_offset_get(DateTimeInterface $object): int {}
8075

81-
/** @return DateInterval|false */
82-
function date_diff(DateTimeInterface $object, DateTimeInterface $object2, bool $absolute = false) {}
76+
function date_diff(
77+
DateTimeInterface $object, DateTimeInterface $object2, bool $absolute = false): DateInterval {}
8378

84-
/** @return DateTime|false */
8579
function date_time_set(
86-
DateTime $object, int $hour, int $minute, int $second = 0, int $microseconds = 0) {}
80+
DateTime $object, int $hour, int $minute, int $second = 0, int $microseconds = 0): DateTime {}
8781

88-
/** @return DateTime|false */
89-
function date_date_set(DateTime $object, int $year, int $month, int $day) {}
82+
function date_date_set(DateTime $object, int $year, int $month, int $day): DateTime {}
9083

91-
/** @return DateTime|false */
92-
function date_isodate_set(DateTime $object, int $year, int $week, int $day = 1) {}
84+
function date_isodate_set(DateTime $object, int $year, int $week, int $day = 1): DateTime {}
9385

94-
/** @return DateTime|false */
95-
function date_timestamp_set(DateTime $object, int $timestamp) {}
86+
function date_timestamp_set(DateTime $object, int $timestamp): DateTime {}
9687

9788
/** @return int|false */
9889
function date_timestamp_get(DateTimeInterface $object) {}
9990

10091
/** @return DateTimeZone|false */
10192
function timezone_open(string $timezone) {}
10293

103-
/** @return string|false */
104-
function timezone_name_get(DateTimeZone $object) {}
94+
function timezone_name_get(DateTimeZone $object): string {}
10595

10696
/** @return string|false */
10797
function timezone_name_from_abbr(string $abbr, int $gmtoffset = -1, int $isdst = -1) {}
10898

109-
/** @return int|false */
110-
function timezone_offset_get(DateTimeZone $object, DateTimeInterface $datetime) {}
99+
function timezone_offset_get(DateTimeZone $object, DateTimeInterface $datetime): int {}
111100

112101
/** @return array|false */
113102
function timezone_transitions_get(
@@ -126,8 +115,7 @@ function timezone_version_get(): string {}
126115
/** @return DateInterval|false */
127116
function date_interval_create_from_date_string(string $time) {}
128117

129-
/** @return string|false */
130-
function date_interval_format(DateInterval $object, string $format) {}
118+
function date_interval_format(DateInterval $object, string $format): string {}
131119

132120
function date_default_timezone_set(string $timezone_identifier): bool {}
133121

@@ -188,25 +176,25 @@ public static function getLastErrors();
188176
/** @return DateTime|false */
189177
public function modify(string $modify);
190178

191-
/** @return DateTime|false */
179+
/** @return DateTime */
192180
public function add(DateInterval $interval);
193181

194-
/** @return DateTime|false */
182+
/** @return DateTime */
195183
public function sub(DateInterval $interval);
196184

197-
/** @return DateTime|false */
185+
/** @return DateTime */
198186
public function setTimezone(DateTimeZone $timezone);
199187

200-
/** @return DateTime|false */
188+
/** @return DateTime */
201189
public function setTime(int $hour, int $minute, int $second = 0, int $microseconds = 0);
202190

203-
/** @return DateTime|false */
191+
/** @return DateTime */
204192
public function setDate(int $year, int $month, int $day);
205193

206-
/** @return DateTime|false */
194+
/** @return DateTime */
207195
public function setISODate(int $year, int $week, int $day = 1);
208196

209-
/** @return DateTime|false */
197+
/** @return DateTime */
210198
public function setTimestamp(int $timestampt);
211199
}
212200

@@ -222,35 +210,35 @@ public static function createFromMutable(DateTime $object);
222210
/** @return DateTimeImmutable|false */
223211
public function modify(string $modify);
224212

225-
/** @return DateTimeImmutable|false */
213+
/** @return DateTimeImmutable */
226214
public function add(DateInterval $interval);
227215

228-
/** @return DateTimeImmutable|false */
216+
/** @return DateTimeImmutable */
229217
public function sub(DateInterval $interval);
230218

231-
/** @return DateTimeImmutable|false */
219+
/** @return DateTimeImmutable */
232220
public function setTimezone(DateTimeZone $timezone);
233221

234-
/** @return DateTimeImmutable|false */
222+
/** @return DateTimeImmutable */
235223
public function setTime(int $hour, int $minute, int $second = 0, int $microseconds = 0);
236224

237-
/** @return DateTimeImmutable|false */
225+
/** @return DateTimeImmutable */
238226
public function setDate(int $year, int $month, int $day);
239227

240-
/** @return DateTimeImmutable|false */
228+
/** @return DateTimeImmutable */
241229
public function setISODate(int $year, int $week, int $day = 1);
242230

243-
/** @return DateTimeImmutable|false */
244-
public function setTimestamp(int $timestampt);
231+
/** @return DateTimeImmutable */
232+
public function setTimestamp(int $timestamp);
245233
}
246234

247235
class DateTimeZone {
248236
public function __construct(string $timezone);
249237

250-
/** @return string|false */
238+
/** @return string */
251239
public function getName();
252240

253-
/** @return int|false */
241+
/** @return int */
254242
public function getOffset(DateTimeInterface $datetime);
255243

256244
/** @return array|false */
@@ -278,7 +266,7 @@ public function __construct(string $interval_spec);
278266
/** @return DateInterval|false */
279267
public static function createFromDateString(string $time);
280268

281-
/** @return string|false */
269+
/** @return string */
282270
public function format(string $format);
283271

284272
public function __wakeup();

ext/date/php_date_arginfo.h

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ ZEND_END_ARG_INFO()
7777
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_get_last_errors, 0, 0, 0)
7878
ZEND_END_ARG_INFO()
7979

80-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format, 0, 0, 2)
80+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date_format, 0, 2, IS_STRING, 0)
8181
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
8282
ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
8383
ZEND_END_ARG_INFO()
@@ -87,7 +87,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2)
8787
ZEND_ARG_TYPE_INFO(0, modify, IS_STRING, 0)
8888
ZEND_END_ARG_INFO()
8989

90-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_add, 0, 0, 2)
90+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_add, 0, 2, DateTime, 0)
9191
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
9292
ZEND_ARG_OBJ_INFO(0, interval, DateInterval, 0)
9393
ZEND_END_ARG_INFO()
@@ -98,42 +98,44 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1)
9898
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
9999
ZEND_END_ARG_INFO()
100100

101-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_set, 0, 0, 2)
101+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_timezone_set, 0, 2, DateTime, 0)
102102
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
103103
ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 0)
104104
ZEND_END_ARG_INFO()
105105

106-
#define arginfo_date_offset_get arginfo_date_timezone_get
106+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date_offset_get, 0, 1, IS_LONG, 0)
107+
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
108+
ZEND_END_ARG_INFO()
107109

108-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_diff, 0, 0, 2)
110+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_diff, 0, 2, DateInterval, 0)
109111
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
110112
ZEND_ARG_OBJ_INFO(0, object2, DateTimeInterface, 0)
111113
ZEND_ARG_TYPE_INFO(0, absolute, _IS_BOOL, 0)
112114
ZEND_END_ARG_INFO()
113115

114-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_time_set, 0, 0, 3)
116+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_time_set, 0, 3, DateTime, 0)
115117
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
116118
ZEND_ARG_TYPE_INFO(0, hour, IS_LONG, 0)
117119
ZEND_ARG_TYPE_INFO(0, minute, IS_LONG, 0)
118120
ZEND_ARG_TYPE_INFO(0, second, IS_LONG, 0)
119121
ZEND_ARG_TYPE_INFO(0, microseconds, IS_LONG, 0)
120122
ZEND_END_ARG_INFO()
121123

122-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_date_set, 0, 0, 4)
124+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_date_set, 0, 4, DateTime, 0)
123125
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
124126
ZEND_ARG_TYPE_INFO(0, year, IS_LONG, 0)
125127
ZEND_ARG_TYPE_INFO(0, month, IS_LONG, 0)
126128
ZEND_ARG_TYPE_INFO(0, day, IS_LONG, 0)
127129
ZEND_END_ARG_INFO()
128130

129-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_isodate_set, 0, 0, 3)
131+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_isodate_set, 0, 3, DateTime, 0)
130132
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
131133
ZEND_ARG_TYPE_INFO(0, year, IS_LONG, 0)
132134
ZEND_ARG_TYPE_INFO(0, week, IS_LONG, 0)
133135
ZEND_ARG_TYPE_INFO(0, day, IS_LONG, 0)
134136
ZEND_END_ARG_INFO()
135137

136-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_set, 0, 0, 2)
138+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_timestamp_set, 0, 2, DateTime, 0)
137139
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
138140
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
139141
ZEND_END_ARG_INFO()
@@ -144,7 +146,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1)
144146
ZEND_ARG_TYPE_INFO(0, timezone, IS_STRING, 0)
145147
ZEND_END_ARG_INFO()
146148

147-
ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_get, 0, 0, 1)
149+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_timezone_name_get, 0, 1, IS_STRING, 0)
148150
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 0)
149151
ZEND_END_ARG_INFO()
150152

@@ -154,7 +156,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_from_abbr, 0, 0, 1)
154156
ZEND_ARG_TYPE_INFO(0, isdst, IS_LONG, 0)
155157
ZEND_END_ARG_INFO()
156158

157-
ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_offset_get, 0, 0, 2)
159+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_timezone_offset_get, 0, 2, IS_LONG, 0)
158160
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 0)
159161
ZEND_ARG_OBJ_INFO(0, datetime, DateTimeInterface, 0)
160162
ZEND_END_ARG_INFO()
@@ -165,7 +167,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_transitions_get, 0, 0, 1)
165167
ZEND_ARG_TYPE_INFO(0, timestamp_end, IS_LONG, 0)
166168
ZEND_END_ARG_INFO()
167169

168-
#define arginfo_timezone_location_get arginfo_timezone_name_get
170+
ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1)
171+
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 0)
172+
ZEND_END_ARG_INFO()
169173

170174
ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0)
171175
ZEND_ARG_TYPE_INFO(0, what, IS_LONG, 0)
@@ -182,7 +186,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_create_from_date_string, 0, 0, 1)
182186
ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
183187
ZEND_END_ARG_INFO()
184188

185-
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_format, 0, 0, 2)
189+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date_interval_format, 0, 2, IS_STRING, 0)
186190
ZEND_ARG_OBJ_INFO(0, object, DateInterval, 0)
187191
ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
188192
ZEND_END_ARG_INFO()
@@ -300,7 +304,9 @@ ZEND_END_ARG_INFO()
300304

301305
#define arginfo_DateTimeImmutable_setISODate arginfo_DateTime_setISODate
302306

303-
#define arginfo_DateTimeImmutable_setTimestamp arginfo_DateTime_setTimestamp
307+
ZEND_BEGIN_ARG_INFO_EX(arginfo_DateTimeImmutable_setTimestamp, 0, 0, 1)
308+
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
309+
ZEND_END_ARG_INFO()
304310

305311
#define arginfo_DateTimeZone___construct arginfo_timezone_open
306312

ext/date/tests/bug48476.phpt

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,28 @@ class MyDateTimeZone extends DateTimeZone {
1010
}
1111

1212
$o = new MyDateTime;
13-
var_dump($o->format("d"));
13+
try {
14+
var_dump($o->format("d"));
15+
} catch (Error $e) {
16+
echo $e->getMessage(), "\n";
17+
}
1418
$x = clone $o;
1519

16-
var_dump($x->format("d"));
20+
try {
21+
var_dump($x->format("d"));
22+
} catch (Error $e) {
23+
echo $e->getMessage(), "\n";
24+
}
1725

1826
clone $o;
1927

20-
21-
var_dump(timezone_location_get(clone new MyDateTimezone));
28+
try {
29+
var_dump(timezone_location_get(clone new MyDateTimezone));
30+
} catch (Error $e) {
31+
echo $e->getMessage(), "\n";
32+
}
2233
?>
23-
--EXPECTF--
24-
Warning: DateTime::format(): The DateTime object has not been correctly initialized by its constructor in %sbug48476.php on line 10
25-
bool(false)
26-
27-
Warning: DateTime::format(): The DateTime object has not been correctly initialized by its constructor in %sbug48476.php on line 13
28-
bool(false)
29-
30-
Warning: timezone_location_get(): The DateTimeZone object has not been correctly initialized by its constructor in %sbug48476.php on line 18
31-
bool(false)
34+
--EXPECT--
35+
The DateTime object has not been correctly initialized by its constructor
36+
The DateTime object has not been correctly initialized by its constructor
37+
The DateTimeZone object has not been correctly initialized by its constructor

ext/date/tests/bug67118.phpt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,9 @@ class mydt extends datetime
2323
new mydt("Funktionsansvarig rådgivning och juridik", "UTC");
2424
?>
2525
--EXPECTF--
26-
Warning: DateTime::format(): The DateTime object has not been correctly initialized by its constructor in %s on line %d
27-
Bad date
26+
Fatal error: Uncaught Error: The DateTime object has not been correctly initialized by its constructor in %s:%d
27+
Stack trace:
28+
#0 %s(%d): DateTime->format('Y')
29+
#1 %s(%d): mydt->__construct(%s)
30+
#2 {main}
31+
thrown in %s on line %d

ext/date/tests/oo_001.phpt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ class _t extends DateTimeZone {
1515
$d = new DateTime;
1616
var_dump($d->format("Y-m-d H:i:s"));
1717

18-
$d = new _d;
19-
var_dump($d->format("Y-m-d H:i:s"));
18+
try {
19+
$d = new _d;
20+
var_dump($d->format("Y-m-d H:i:s"));
21+
} catch (Error $e) {
22+
echo $e->getMessage(),"\n";
23+
}
2024

2125
try {
2226
new DateTime("1am todax");
@@ -27,8 +31,12 @@ try {
2731
$t = new DateTimeZone("UTC");
2832
var_dump($t->getName());
2933

30-
$t = new _t;
31-
var_dump($t->getName());
34+
try {
35+
$t = new _t;
36+
var_dump($t->getName());
37+
} catch (Error $e) {
38+
echo $e->getMessage(),"\n";
39+
}
3240

3341
try {
3442
new DateTimeZone("GottaFindThisOne");
@@ -40,13 +48,9 @@ echo "DONE\n";
4048
?>
4149
--EXPECTF--
4250
string(19) "%d-%d-%d %d:%d:%d"
43-
44-
Warning: DateTime::format(): The DateTime object has not been correctly initialized by its constructor in %soo_001.php on line %d
45-
bool(false)
51+
The DateTime object has not been correctly initialized by its constructor
4652
DateTime::__construct(): Failed to parse time string (1am todax) at position 4 (t): The timezone could not be found in the database
4753
string(3) "UTC"
48-
49-
Warning: DateTimeZone::getName(): The DateTimeZone object has not been correctly initialized by its constructor in %soo_001.php on line %d
50-
bool(false)
54+
The DateTimeZone object has not been correctly initialized by its constructor
5155
DateTimeZone::__construct(): Unknown or bad timezone (GottaFindThisOne)
5256
DONE

0 commit comments

Comments
 (0)