/src/php-src/ext/date/time_duration.c
Line | Count | Source |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Copyright © The PHP Group and Contributors. | |
4 | | +----------------------------------------------------------------------+ |
5 | | | This source file is subject to the Modified BSD License that is | |
6 | | | bundled with this package in the file LICENSE, and is available | |
7 | | | through the World Wide Web at <https://www.php.net/license/>. | |
8 | | | | |
9 | | | SPDX-License-Identifier: BSD-3-Clause | |
10 | | +----------------------------------------------------------------------+ |
11 | | | Authors: Derick Rethans <derick@derickrethans.nl> | |
12 | | | Tim Düsterhus <timwolla@php.net> | |
13 | | +----------------------------------------------------------------------+ |
14 | | */ |
15 | | |
16 | | #include "php.h" |
17 | | #include "Zend/zend_exceptions.h" |
18 | | |
19 | | #include "php_date.h" |
20 | | #include "php_time.h" |
21 | | #include "time_duration.h" |
22 | | |
23 | 0 | #define NANOS_IN_SEC 1000000000 |
24 | 0 | #define NANOS_IN_MICRO 1000 |
25 | 0 | #define MICROS_IN_SEC 1000000 |
26 | 0 | #define NANOS_IN_MILLI 1000000 |
27 | 0 | #define MILLIS_IN_SEC 1000 |
28 | | |
29 | | static_assert(NANOS_IN_MICRO * MICROS_IN_SEC == NANOS_IN_SEC, ""); |
30 | | static_assert(NANOS_IN_MILLI * MILLIS_IN_SEC == NANOS_IN_SEC, ""); |
31 | | |
32 | 0 | #define Z_PARAM_ULONG(l) { \ |
33 | 0 | zend_long __##l; \ |
34 | 0 | Z_PARAM_LONG(__##l); \ |
35 | 0 | if (__##l < 0) { \ |
36 | 0 | zend_argument_value_error(_i, "must be greater than or equal to 0"); \ |
37 | 0 | _error_code = ZPP_ERROR_FAILURE; \ |
38 | 0 | break; \ |
39 | 0 | } \ |
40 | 0 | l = __##l; \ |
41 | 0 | } |
42 | | |
43 | | ZEND_COLD static void throw_out_of_range_exception(void) |
44 | 0 | { |
45 | 0 | #if SIZEOF_ZEND_LONG != 4 |
46 | 0 | zend_throw_exception(php_date_ce_time_timeexception, "The maximum representable range is 9_223_372_035 seconds (roughly 292 years)", 0); |
47 | | #else |
48 | | zend_throw_exception(php_date_ce_time_timeexception, "The maximum representable range is 2_147_483_647 seconds (roughly 68 years)", 0); |
49 | | #endif |
50 | 0 | } |
51 | | |
52 | | ZEND_COLD static void throw_timelib_error(int error) |
53 | 0 | { |
54 | 0 | switch (error) { |
55 | 0 | case TIMELIB_ERROR_SECONDS_OUT_OF_RANGE: |
56 | 0 | throw_out_of_range_exception(); |
57 | 0 | break; |
58 | 0 | case TIMELIB_ERROR_DIVISION_BY_ZERO: |
59 | 0 | zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); |
60 | 0 | break; |
61 | 0 | case TIMELIB_ERROR_ISO8601_DURATION_PARSE_FAILURE: |
62 | 0 | case TIMELIB_ERROR_DURATION_MISSING_PERIOD: |
63 | 0 | case TIMELIB_ERROR_DURATION_ONLY_PERIOD_ALLOWED: |
64 | 0 | case TIMELIB_ERROR_DURATION_DAYS_FOUND: |
65 | 0 | zend_throw_exception(php_date_ce_time_timeexception, timelib_get_error_message(error), 0); |
66 | 0 | break; |
67 | 0 | default: |
68 | | /* This should be unreachable in practice. */ |
69 | 0 | zend_throw_exception_ex(php_date_ce_time_timeexception, 0, "Failed to create a Time\\Duration: %s", timelib_get_error_message(error)); |
70 | 0 | break; |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | static inline php_date_time_duration *create_duration_shell(zval *target) |
75 | 0 | { |
76 | 0 | object_init_ex(target, php_date_ce_time_duration); |
77 | |
|
78 | 0 | return Z_DATE_TIME_DURATION_P(target); |
79 | 0 | } |
80 | | |
81 | | static inline bool duration_representable(const timelib_duration *duration) |
82 | 0 | { |
83 | 0 | return |
84 | | /* Check if the duration would overflow the $seconds property. */ |
85 | 0 | duration->seconds <= ((uint64_t)ZEND_LONG_MAX) |
86 | | /* This constraint is an explicit part of PHP's API: It is the maximum $seconds |
87 | | * value that allows storing the entire duration as a single int64_t counting |
88 | | * nanoseconds, which might be desirable in the future when userland `int` is |
89 | | * consistently 64 bits. |
90 | | * |
91 | | * While it is currently also enforced by timelib, this might change |
92 | | * in a future version of timelib, thus we also enforce it manually. */ |
93 | 0 | && duration->seconds <= UINT64_C(9223372035); |
94 | 0 | } |
95 | | |
96 | | ZEND_ATTRIBUTE_NODISCARD static inline zend_result sync_properties(php_date_time_duration *object) |
97 | 0 | { |
98 | 0 | if (!duration_representable(&object->duration)) { |
99 | 0 | throw_out_of_range_exception(); |
100 | 0 | return FAILURE; |
101 | 0 | } |
102 | | |
103 | 0 | ZEND_ASSERT(Z_ISUNDEF_P(OBJ_PROP_NUM(&object->std, 0))); |
104 | 0 | ZEND_ASSERT(Z_ISUNDEF_P(OBJ_PROP_NUM(&object->std, 1))); |
105 | 0 | ZEND_ASSERT(Z_ISUNDEF_P(OBJ_PROP_NUM(&object->std, 2))); |
106 | |
|
107 | 0 | ZVAL_LONG(OBJ_PROP_NUM(&object->std, 0), object->duration.seconds); |
108 | 0 | Z_PROP_FLAG_P(OBJ_PROP_NUM(&object->std, 0)) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE); |
109 | 0 | ZVAL_LONG(OBJ_PROP_NUM(&object->std, 1), object->duration.nanoseconds); |
110 | 0 | Z_PROP_FLAG_P(OBJ_PROP_NUM(&object->std, 1)) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE); |
111 | 0 | ZVAL_BOOL(OBJ_PROP_NUM(&object->std, 2), object->duration.negative); |
112 | 0 | Z_PROP_FLAG_P(OBJ_PROP_NUM(&object->std, 2)) &= ~(IS_PROP_UNINIT|IS_PROP_REINITABLE); |
113 | |
|
114 | 0 | return SUCCESS; |
115 | 0 | } |
116 | | |
117 | | ZEND_ATTRIBUTE_NODISCARD PHPAPI zend_result php_date_time_duration_create(zval *target, zend_ulong seconds, zend_ulong nanoseconds) |
118 | 0 | { |
119 | 0 | ZEND_ASSERT(nanoseconds < NANOS_IN_SEC); |
120 | |
|
121 | 0 | if (EXPECTED(DATEG(duration_cache))) { |
122 | 0 | php_date_time_duration *cached = php_date_time_duration_from_obj(DATEG(duration_cache)); |
123 | 0 | ZEND_ASSERT(!cached->duration.negative); |
124 | |
|
125 | 0 | if (cached->duration.seconds == seconds && cached->duration.nanoseconds == nanoseconds) { |
126 | 0 | ZVAL_OBJ_COPY(target, &cached->std); |
127 | 0 | return SUCCESS; |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | 0 | php_date_time_duration *obj = create_duration_shell(target); |
132 | |
|
133 | 0 | int error = timelib_duration_ctor_static(&obj->duration, seconds, nanoseconds, /* negative */ false); |
134 | 0 | if (error != TIMELIB_ERROR_NO_ERROR) { |
135 | 0 | throw_timelib_error(error); |
136 | 0 | return FAILURE; |
137 | 0 | } |
138 | | |
139 | 0 | if (sync_properties(obj) == FAILURE) { |
140 | 0 | return FAILURE; |
141 | 0 | } |
142 | | |
143 | 0 | if (DATEG(duration_cache)) { |
144 | 0 | zend_object_release(DATEG(duration_cache)); |
145 | 0 | } |
146 | 0 | DATEG(duration_cache) = zend_object_copy(&obj->std); |
147 | |
|
148 | 0 | return SUCCESS; |
149 | 0 | } |
150 | | |
151 | | PHP_METHOD(Time_Duration, __construct) |
152 | 0 | { |
153 | 0 | zend_throw_error(NULL, "Cannot directly construct Time\\Duration, use Time\\Duration::from*() methods instead"); |
154 | 0 | } |
155 | | |
156 | | PHP_METHOD(Time_Duration, __unserialize) |
157 | 15 | { |
158 | 15 | php_date_time_duration *duration = Z_DATE_TIME_DURATION_P(ZEND_THIS); |
159 | | |
160 | 15 | HashTable *data; |
161 | | |
162 | 45 | ZEND_PARSE_PARAMETERS_START(1, 1) |
163 | 60 | Z_PARAM_ARRAY_HT(data); |
164 | 15 | ZEND_PARSE_PARAMETERS_END(); |
165 | | |
166 | 15 | object_properties_load(&duration->std, data); |
167 | 15 | if (EG(exception)) { |
168 | 11 | goto fail; |
169 | 11 | } |
170 | | |
171 | 4 | zval *seconds = OBJ_PROP_NUM(&duration->std, 0); |
172 | 4 | zval *nanoseconds = OBJ_PROP_NUM(&duration->std, 1); |
173 | 4 | zval *negative = OBJ_PROP_NUM(&duration->std, 2); |
174 | 4 | if (Z_ISUNDEF_P(seconds) || Z_ISUNDEF_P(nanoseconds) || Z_ISUNDEF_P(negative)) { |
175 | 4 | goto fail; |
176 | 4 | } |
177 | | |
178 | | /* Verify that both properties are non-negative, since the timelib_duration_ctor_static() takes |
179 | | * unsigned. */ |
180 | 0 | if (Z_LVAL_P(seconds) < 0 || Z_LVAL_P(nanoseconds) < 0) { |
181 | 0 | goto fail; |
182 | 0 | } |
183 | | |
184 | | /* timelib_duration_ctor_static() takes a uint32_t for nanoseconds, so larger values would |
185 | | * implicitly wrap around instead of being rejected. */ |
186 | 0 | if (Z_LVAL_P(nanoseconds) >= NANOS_IN_SEC) { |
187 | 0 | goto fail; |
188 | 0 | } |
189 | | |
190 | 0 | int error = timelib_duration_ctor_static(&duration->duration, Z_LVAL_P(seconds), Z_LVAL_P(nanoseconds), Z_TYPE_P(negative) == IS_TRUE); |
191 | 0 | if (error != TIMELIB_ERROR_NO_ERROR) { |
192 | 0 | throw_timelib_error(error); |
193 | 0 | goto fail; |
194 | 0 | } |
195 | | |
196 | 0 | if (!duration_representable(&duration->duration)) { |
197 | 0 | throw_out_of_range_exception(); |
198 | 0 | goto fail; |
199 | 0 | } |
200 | | |
201 | 0 | if ((Z_TYPE_P(negative) == IS_TRUE) != duration->duration.negative) { |
202 | 0 | goto fail; |
203 | 0 | } |
204 | | |
205 | 0 | return; |
206 | | |
207 | 15 | fail: |
208 | | |
209 | | /* If an exception is already active (e.g. for unrepresentable durations) it will be wrapped for |
210 | | * uniform exceptions thrown from unserialization handlers, but to still provide additional |
211 | | * context for a human reader. */ |
212 | 15 | zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(duration->std.ce->name)); |
213 | 15 | RETURN_THROWS(); |
214 | 15 | } |
215 | | |
216 | | PHP_METHOD(Time_Duration, fromSeconds) |
217 | 0 | { |
218 | 0 | zend_ulong seconds; |
219 | 0 | zend_ulong nanoseconds = 0; |
220 | |
|
221 | 0 | ZEND_PARSE_PARAMETERS_START(1, 2) |
222 | 0 | Z_PARAM_ULONG(seconds); |
223 | 0 | Z_PARAM_OPTIONAL; |
224 | 0 | Z_PARAM_ULONG(nanoseconds); |
225 | 0 | ZEND_PARSE_PARAMETERS_END(); |
226 | | |
227 | 0 | if (nanoseconds >= NANOS_IN_SEC) { |
228 | 0 | zend_argument_value_error(2, "must be less than 1_000_000_000"); |
229 | 0 | RETURN_THROWS(); |
230 | 0 | } |
231 | | |
232 | 0 | if (php_date_time_duration_create(return_value, seconds, nanoseconds) == FAILURE) { |
233 | 0 | RETURN_THROWS(); |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | PHP_METHOD(Time_Duration, fromNanoseconds) |
238 | 0 | { |
239 | 0 | zend_ulong nanoseconds; |
240 | |
|
241 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
242 | 0 | Z_PARAM_ULONG(nanoseconds); |
243 | 0 | ZEND_PARSE_PARAMETERS_END(); |
244 | | |
245 | 0 | zend_ulong seconds = nanoseconds / NANOS_IN_SEC; |
246 | 0 | nanoseconds %= NANOS_IN_SEC; |
247 | |
|
248 | 0 | if (php_date_time_duration_create(return_value, seconds, nanoseconds) == FAILURE) { |
249 | 0 | RETURN_THROWS(); |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | | PHP_METHOD(Time_Duration, fromMicroseconds) |
254 | 0 | { |
255 | 0 | zend_ulong microseconds; |
256 | |
|
257 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
258 | 0 | Z_PARAM_ULONG(microseconds); |
259 | 0 | ZEND_PARSE_PARAMETERS_END(); |
260 | | |
261 | 0 | zend_ulong seconds = microseconds / MICROS_IN_SEC; |
262 | 0 | zend_ulong nanoseconds = (microseconds % MICROS_IN_SEC) * NANOS_IN_MICRO; |
263 | |
|
264 | 0 | if (php_date_time_duration_create(return_value, seconds, nanoseconds) == FAILURE) { |
265 | 0 | RETURN_THROWS(); |
266 | 0 | } |
267 | 0 | } |
268 | | |
269 | | PHP_METHOD(Time_Duration, fromMilliseconds) |
270 | 0 | { |
271 | 0 | zend_ulong milliseconds; |
272 | |
|
273 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
274 | 0 | Z_PARAM_ULONG(milliseconds); |
275 | 0 | ZEND_PARSE_PARAMETERS_END(); |
276 | | |
277 | 0 | zend_ulong seconds = milliseconds / MILLIS_IN_SEC; |
278 | 0 | zend_ulong nanoseconds = (milliseconds % MILLIS_IN_SEC) * NANOS_IN_MILLI; |
279 | |
|
280 | 0 | if (php_date_time_duration_create(return_value, seconds, nanoseconds) == FAILURE) { |
281 | 0 | RETURN_THROWS(); |
282 | 0 | } |
283 | 0 | } |
284 | | |
285 | | PHP_METHOD(Time_Duration, fromMinutes) |
286 | 0 | { |
287 | 0 | zend_ulong minutes; |
288 | |
|
289 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
290 | 0 | Z_PARAM_ULONG(minutes); |
291 | 0 | ZEND_PARSE_PARAMETERS_END(); |
292 | | |
293 | 0 | if (minutes > (ZEND_ULONG_MAX / 60)) { |
294 | 0 | throw_out_of_range_exception(); |
295 | 0 | RETURN_THROWS(); |
296 | 0 | } |
297 | | |
298 | 0 | if (php_date_time_duration_create(return_value, minutes * 60, /* nanoseconds */ 0) == FAILURE) { |
299 | 0 | RETURN_THROWS(); |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | PHP_METHOD(Time_Duration, fromHours) |
304 | 0 | { |
305 | 0 | zend_ulong hours; |
306 | |
|
307 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
308 | 0 | Z_PARAM_ULONG(hours); |
309 | 0 | ZEND_PARSE_PARAMETERS_END(); |
310 | | |
311 | 0 | if (hours > (ZEND_ULONG_MAX / 3600)) { |
312 | 0 | throw_out_of_range_exception(); |
313 | 0 | RETURN_THROWS(); |
314 | 0 | } |
315 | | |
316 | 0 | if (php_date_time_duration_create(return_value, hours * 3600, /* nanoseconds */ 0) == FAILURE) { |
317 | 0 | RETURN_THROWS(); |
318 | 0 | } |
319 | 0 | } |
320 | | |
321 | | PHP_METHOD(Time_Duration, fromIso8601DurationString) |
322 | 0 | { |
323 | 0 | zend_string *specification; |
324 | |
|
325 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
326 | 0 | Z_PARAM_STR(specification); |
327 | 0 | ZEND_PARSE_PARAMETERS_END(); |
328 | | |
329 | 0 | if (zend_str_has_nul_byte(specification)) { |
330 | 0 | throw_timelib_error(TIMELIB_ERROR_ISO8601_DURATION_PARSE_FAILURE); |
331 | 0 | RETURN_THROWS(); |
332 | 0 | } |
333 | | |
334 | 0 | int error; |
335 | 0 | timelib_duration *d = timelib_duration_create_from_iso8601string(ZSTR_VAL(specification), &error); |
336 | 0 | if (error != TIMELIB_ERROR_NO_ERROR) { |
337 | 0 | throw_timelib_error(error); |
338 | 0 | RETURN_THROWS(); |
339 | 0 | } |
340 | | |
341 | 0 | php_date_time_duration *new = create_duration_shell(return_value); |
342 | 0 | new->duration = *d; |
343 | 0 | timelib_duration_dtor(d); |
344 | |
|
345 | 0 | if (sync_properties(new) == FAILURE) { |
346 | 0 | RETURN_THROWS(); |
347 | 0 | } |
348 | 0 | } |
349 | | |
350 | | PHP_METHOD(Time_Duration, negate) |
351 | 0 | { |
352 | 0 | const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); |
353 | |
|
354 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
355 | | |
356 | 0 | php_date_time_duration *new = create_duration_shell(return_value); |
357 | |
|
358 | 0 | int error = timelib_duration_negate_static(&new->duration, &original->duration); |
359 | 0 | if (error != TIMELIB_ERROR_NO_ERROR) { |
360 | 0 | throw_timelib_error(error); |
361 | 0 | RETURN_THROWS(); |
362 | 0 | } |
363 | | |
364 | 0 | if (sync_properties(new) == FAILURE) { |
365 | 0 | RETURN_THROWS(); |
366 | 0 | } |
367 | 0 | } |
368 | | |
369 | | PHP_METHOD(Time_Duration, absolute) |
370 | 0 | { |
371 | 0 | const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); |
372 | |
|
373 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
374 | | |
375 | 0 | if (!original->duration.negative) { |
376 | 0 | RETURN_COPY(ZEND_THIS); |
377 | 0 | } |
378 | | |
379 | 0 | if (php_date_time_duration_create(return_value, original->duration.seconds, original->duration.nanoseconds) == FAILURE) { |
380 | 0 | RETURN_THROWS(); |
381 | 0 | } |
382 | 0 | } |
383 | | |
384 | | PHP_METHOD(Time_Duration, add) |
385 | 0 | { |
386 | 0 | const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); |
387 | |
|
388 | 0 | const php_date_time_duration *additional; |
389 | |
|
390 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
391 | 0 | Z_PARAM_DATE_TIME_DURATION(additional); |
392 | 0 | ZEND_PARSE_PARAMETERS_END(); |
393 | | |
394 | 0 | php_date_time_duration *new = create_duration_shell(return_value); |
395 | |
|
396 | 0 | int error = timelib_duration_add_static(&new->duration, &original->duration, &additional->duration); |
397 | 0 | if (error != TIMELIB_ERROR_NO_ERROR) { |
398 | 0 | throw_timelib_error(error); |
399 | 0 | RETURN_THROWS(); |
400 | 0 | } |
401 | | |
402 | 0 | if (sync_properties(new) == FAILURE) { |
403 | 0 | RETURN_THROWS(); |
404 | 0 | } |
405 | 0 | } |
406 | | |
407 | | PHP_METHOD(Time_Duration, sub) |
408 | 0 | { |
409 | 0 | const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); |
410 | |
|
411 | 0 | const php_date_time_duration *minus; |
412 | |
|
413 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
414 | 0 | Z_PARAM_DATE_TIME_DURATION(minus); |
415 | 0 | ZEND_PARSE_PARAMETERS_END(); |
416 | | |
417 | 0 | php_date_time_duration *new = create_duration_shell(return_value); |
418 | |
|
419 | 0 | int error = timelib_duration_sub_static(&new->duration, &original->duration, &minus->duration); |
420 | 0 | if (error != TIMELIB_ERROR_NO_ERROR) { |
421 | 0 | throw_timelib_error(error); |
422 | 0 | RETURN_THROWS(); |
423 | 0 | } |
424 | | |
425 | 0 | if (sync_properties(new) == FAILURE) { |
426 | 0 | RETURN_THROWS(); |
427 | 0 | } |
428 | 0 | } |
429 | | |
430 | | PHP_METHOD(Time_Duration, multiplyBy) |
431 | 0 | { |
432 | 0 | const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); |
433 | |
|
434 | 0 | zend_ulong factor; |
435 | |
|
436 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
437 | 0 | Z_PARAM_ULONG(factor); |
438 | 0 | ZEND_PARSE_PARAMETERS_END(); |
439 | | |
440 | 0 | php_date_time_duration *new = create_duration_shell(return_value); |
441 | |
|
442 | 0 | int error = timelib_duration_mul_static(&new->duration, &original->duration, factor); |
443 | 0 | if (error != TIMELIB_ERROR_NO_ERROR) { |
444 | 0 | throw_timelib_error(error); |
445 | 0 | RETURN_THROWS(); |
446 | 0 | } |
447 | | |
448 | 0 | if (sync_properties(new) == FAILURE) { |
449 | 0 | RETURN_THROWS(); |
450 | 0 | } |
451 | 0 | } |
452 | | |
453 | | PHP_METHOD(Time_Duration, divideBy) |
454 | 0 | { |
455 | 0 | const php_date_time_duration *original = Z_DATE_TIME_DURATION_P(ZEND_THIS); |
456 | |
|
457 | 0 | zend_ulong divisor; |
458 | |
|
459 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
460 | 0 | Z_PARAM_ULONG(divisor); |
461 | 0 | ZEND_PARSE_PARAMETERS_END(); |
462 | | |
463 | 0 | php_date_time_duration *new = create_duration_shell(return_value); |
464 | |
|
465 | 0 | int error = timelib_duration_div_static(&new->duration, &original->duration, divisor); |
466 | 0 | if (error != TIMELIB_ERROR_NO_ERROR) { |
467 | 0 | throw_timelib_error(error); |
468 | 0 | RETURN_THROWS(); |
469 | 0 | } |
470 | | |
471 | 0 | if (sync_properties(new) == FAILURE) { |
472 | 0 | RETURN_THROWS(); |
473 | 0 | } |
474 | 0 | } |
475 | | |
476 | | PHP_METHOD(Time_Duration, compare) |
477 | 0 | { |
478 | 0 | const php_date_time_duration *a; |
479 | 0 | const php_date_time_duration *b; |
480 | |
|
481 | 0 | ZEND_PARSE_PARAMETERS_START(2, 2) |
482 | 0 | Z_PARAM_DATE_TIME_DURATION(a); |
483 | 0 | Z_PARAM_DATE_TIME_DURATION(b); |
484 | 0 | ZEND_PARSE_PARAMETERS_END(); |
485 | | |
486 | 0 | RETURN_LONG(timelib_duration_compare(&a->duration, &b->duration)); |
487 | 0 | } |