1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 08:12:21 +01:00

Make uninitialized DateTime an Error

This avoids many spurious false return values.
This commit is contained in:
Nikita Popov
2019-08-09 14:33:59 +02:00
parent 33886f710c
commit 3b2f2ce474
8 changed files with 106 additions and 92 deletions

View File

@@ -303,8 +303,8 @@ static zend_object_handlers date_object_handlers_period;
#define DATE_CHECK_INITIALIZED(member, class_name) \
if (!(member)) { \
php_error_docref(NULL, E_WARNING, "The " #class_name " object has not been correctly initialized by its constructor"); \
RETURN_FALSE; \
zend_throw_error(NULL, "The " #class_name " object has not been correctly initialized by its constructor"); \
return; \
}
static void date_object_free_storage_date(zend_object *object);

View File

@@ -57,42 +57,33 @@ function date_parse_from_format(string $format, string $date): array {}
/** @return array|false */
function date_get_last_errors() {}
/** @return string|false */
function date_format(DateTimeInterface $object, string $format) {}
function date_format(DateTimeInterface $object, string $format): string {}
/** @return DateTime|false */
function date_modify(DateTime $object, string $modify) {}
/** @return DateTime|false */
function date_add(DateTime $object, DateInterval $interval) {}
function date_add(DateTime $object, DateInterval $interval): DateTime {}
/** @return DateTime|false */
function date_sub(DateTime $object, DateInterval $interval) {}
function date_sub(DateTime $object, DateInterval $interval): DateTime {}
/** @return DateTimeZone|false */
function date_timezone_get(DateTimeInterface $object) {}
/** @return DateTime|false */
function date_timezone_set(DateTimeInterface $object, DateTimeZone $timezone) {}
function date_timezone_set(DateTimeInterface $object, DateTimeZone $timezone): DateTime {}
/** @return int|false */
function date_offset_get(DateTimeInterface $object) {}
function date_offset_get(DateTimeInterface $object): int {}
/** @return DateInterval|false */
function date_diff(DateTimeInterface $object, DateTimeInterface $object2, bool $absolute = false) {}
function date_diff(
DateTimeInterface $object, DateTimeInterface $object2, bool $absolute = false): DateInterval {}
/** @return DateTime|false */
function date_time_set(
DateTime $object, int $hour, int $minute, int $second = 0, int $microseconds = 0) {}
DateTime $object, int $hour, int $minute, int $second = 0, int $microseconds = 0): DateTime {}
/** @return DateTime|false */
function date_date_set(DateTime $object, int $year, int $month, int $day) {}
function date_date_set(DateTime $object, int $year, int $month, int $day): DateTime {}
/** @return DateTime|false */
function date_isodate_set(DateTime $object, int $year, int $week, int $day = 1) {}
function date_isodate_set(DateTime $object, int $year, int $week, int $day = 1): DateTime {}
/** @return DateTime|false */
function date_timestamp_set(DateTime $object, int $timestamp) {}
function date_timestamp_set(DateTime $object, int $timestamp): DateTime {}
/** @return int|false */
function date_timestamp_get(DateTimeInterface $object) {}
@@ -100,14 +91,12 @@ function date_timestamp_get(DateTimeInterface $object) {}
/** @return DateTimeZone|false */
function timezone_open(string $timezone) {}
/** @return string|false */
function timezone_name_get(DateTimeZone $object) {}
function timezone_name_get(DateTimeZone $object): string {}
/** @return string|false */
function timezone_name_from_abbr(string $abbr, int $gmtoffset = -1, int $isdst = -1) {}
/** @return int|false */
function timezone_offset_get(DateTimeZone $object, DateTimeInterface $datetime) {}
function timezone_offset_get(DateTimeZone $object, DateTimeInterface $datetime): int {}
/** @return array|false */
function timezone_transitions_get(
@@ -126,8 +115,7 @@ function timezone_version_get(): string {}
/** @return DateInterval|false */
function date_interval_create_from_date_string(string $time) {}
/** @return string|false */
function date_interval_format(DateInterval $object, string $format) {}
function date_interval_format(DateInterval $object, string $format): string {}
function date_default_timezone_set(string $timezone_identifier): bool {}
@@ -188,25 +176,25 @@ class DateTime implements DateTimeInterface {
/** @return DateTime|false */
public function modify(string $modify);
/** @return DateTime|false */
/** @return DateTime */
public function add(DateInterval $interval);
/** @return DateTime|false */
/** @return DateTime */
public function sub(DateInterval $interval);
/** @return DateTime|false */
/** @return DateTime */
public function setTimezone(DateTimeZone $timezone);
/** @return DateTime|false */
/** @return DateTime */
public function setTime(int $hour, int $minute, int $second = 0, int $microseconds = 0);
/** @return DateTime|false */
/** @return DateTime */
public function setDate(int $year, int $month, int $day);
/** @return DateTime|false */
/** @return DateTime */
public function setISODate(int $year, int $week, int $day = 1);
/** @return DateTime|false */
/** @return DateTime */
public function setTimestamp(int $timestampt);
}
@@ -222,35 +210,35 @@ class DateTimeImmutable implements DateTimeInterface {
/** @return DateTimeImmutable|false */
public function modify(string $modify);
/** @return DateTimeImmutable|false */
/** @return DateTimeImmutable */
public function add(DateInterval $interval);
/** @return DateTimeImmutable|false */
/** @return DateTimeImmutable */
public function sub(DateInterval $interval);
/** @return DateTimeImmutable|false */
/** @return DateTimeImmutable */
public function setTimezone(DateTimeZone $timezone);
/** @return DateTimeImmutable|false */
/** @return DateTimeImmutable */
public function setTime(int $hour, int $minute, int $second = 0, int $microseconds = 0);
/** @return DateTimeImmutable|false */
/** @return DateTimeImmutable */
public function setDate(int $year, int $month, int $day);
/** @return DateTimeImmutable|false */
/** @return DateTimeImmutable */
public function setISODate(int $year, int $week, int $day = 1);
/** @return DateTimeImmutable|false */
public function setTimestamp(int $timestampt);
/** @return DateTimeImmutable */
public function setTimestamp(int $timestamp);
}
class DateTimeZone {
public function __construct(string $timezone);
/** @return string|false */
/** @return string */
public function getName();
/** @return int|false */
/** @return int */
public function getOffset(DateTimeInterface $datetime);
/** @return array|false */
@@ -278,7 +266,7 @@ class DateInterval {
/** @return DateInterval|false */
public static function createFromDateString(string $time);
/** @return string|false */
/** @return string */
public function format(string $format);
public function __wakeup();

View File

@@ -77,7 +77,7 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_get_last_errors, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_format, 0, 0, 2)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date_format, 0, 2, IS_STRING, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
ZEND_END_ARG_INFO()
@@ -87,7 +87,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_date_modify, 0, 0, 2)
ZEND_ARG_TYPE_INFO(0, modify, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_add, 0, 0, 2)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_add, 0, 2, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, interval, DateInterval, 0)
ZEND_END_ARG_INFO()
@@ -98,20 +98,22 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_get, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timezone_set, 0, 0, 2)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_timezone_set, 0, 2, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 0)
ZEND_END_ARG_INFO()
#define arginfo_date_offset_get arginfo_date_timezone_get
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date_offset_get, 0, 1, IS_LONG, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_diff, 0, 0, 2)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_diff, 0, 2, DateInterval, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
ZEND_ARG_OBJ_INFO(0, object2, DateTimeInterface, 0)
ZEND_ARG_TYPE_INFO(0, absolute, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_time_set, 0, 0, 3)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_time_set, 0, 3, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
ZEND_ARG_TYPE_INFO(0, hour, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, minute, IS_LONG, 0)
@@ -119,21 +121,21 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_date_time_set, 0, 0, 3)
ZEND_ARG_TYPE_INFO(0, microseconds, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_date_set, 0, 0, 4)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_date_set, 0, 4, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
ZEND_ARG_TYPE_INFO(0, year, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, month, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, day, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_isodate_set, 0, 0, 3)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_isodate_set, 0, 3, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
ZEND_ARG_TYPE_INFO(0, year, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, week, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, day, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_timestamp_set, 0, 0, 2)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_timestamp_set, 0, 2, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
ZEND_END_ARG_INFO()
@@ -144,7 +146,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_open, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, timezone, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_get, 0, 0, 1)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_timezone_name_get, 0, 1, IS_STRING, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 0)
ZEND_END_ARG_INFO()
@@ -154,7 +156,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_name_from_abbr, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, isdst, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_offset_get, 0, 0, 2)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_timezone_offset_get, 0, 2, IS_LONG, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 0)
ZEND_ARG_OBJ_INFO(0, datetime, DateTimeInterface, 0)
ZEND_END_ARG_INFO()
@@ -165,7 +167,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_transitions_get, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, timestamp_end, IS_LONG, 0)
ZEND_END_ARG_INFO()
#define arginfo_timezone_location_get arginfo_timezone_name_get
ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, object, DateTimeZone, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0)
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)
ZEND_ARG_TYPE_INFO(0, time, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_date_interval_format, 0, 0, 2)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_date_interval_format, 0, 2, IS_STRING, 0)
ZEND_ARG_OBJ_INFO(0, object, DateInterval, 0)
ZEND_ARG_TYPE_INFO(0, format, IS_STRING, 0)
ZEND_END_ARG_INFO()
@@ -300,7 +304,9 @@ ZEND_END_ARG_INFO()
#define arginfo_DateTimeImmutable_setISODate arginfo_DateTime_setISODate
#define arginfo_DateTimeImmutable_setTimestamp arginfo_DateTime_setTimestamp
ZEND_BEGIN_ARG_INFO_EX(arginfo_DateTimeImmutable_setTimestamp, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, timestamp, IS_LONG, 0)
ZEND_END_ARG_INFO()
#define arginfo_DateTimeZone___construct arginfo_timezone_open

View File

@@ -10,22 +10,28 @@ class MyDateTimeZone extends DateTimeZone {
}
$o = new MyDateTime;
var_dump($o->format("d"));
try {
var_dump($o->format("d"));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
$x = clone $o;
var_dump($x->format("d"));
try {
var_dump($x->format("d"));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
clone $o;
var_dump(timezone_location_get(clone new MyDateTimezone));
try {
var_dump(timezone_location_get(clone new MyDateTimezone));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECTF--
Warning: DateTime::format(): The DateTime object has not been correctly initialized by its constructor in %sbug48476.php on line 10
bool(false)
Warning: DateTime::format(): The DateTime object has not been correctly initialized by its constructor in %sbug48476.php on line 13
bool(false)
Warning: timezone_location_get(): The DateTimeZone object has not been correctly initialized by its constructor in %sbug48476.php on line 18
bool(false)
--EXPECT--
The DateTime object has not been correctly initialized by its constructor
The DateTime object has not been correctly initialized by its constructor
The DateTimeZone object has not been correctly initialized by its constructor

View File

@@ -23,5 +23,9 @@ class mydt extends datetime
new mydt("Funktionsansvarig rådgivning och juridik", "UTC");
?>
--EXPECTF--
Warning: DateTime::format(): The DateTime object has not been correctly initialized by its constructor in %s on line %d
Bad date
Fatal error: Uncaught Error: The DateTime object has not been correctly initialized by its constructor in %s:%d
Stack trace:
#0 %s(%d): DateTime->format('Y')
#1 %s(%d): mydt->__construct(%s)
#2 {main}
thrown in %s on line %d

View File

@@ -15,8 +15,12 @@ class _t extends DateTimeZone {
$d = new DateTime;
var_dump($d->format("Y-m-d H:i:s"));
$d = new _d;
var_dump($d->format("Y-m-d H:i:s"));
try {
$d = new _d;
var_dump($d->format("Y-m-d H:i:s"));
} catch (Error $e) {
echo $e->getMessage(),"\n";
}
try {
new DateTime("1am todax");
@@ -27,8 +31,12 @@ try {
$t = new DateTimeZone("UTC");
var_dump($t->getName());
$t = new _t;
var_dump($t->getName());
try {
$t = new _t;
var_dump($t->getName());
} catch (Error $e) {
echo $e->getMessage(),"\n";
}
try {
new DateTimeZone("GottaFindThisOne");
@@ -40,13 +48,9 @@ echo "DONE\n";
?>
--EXPECTF--
string(19) "%d-%d-%d %d:%d:%d"
Warning: DateTime::format(): The DateTime object has not been correctly initialized by its constructor in %soo_001.php on line %d
bool(false)
The DateTime object has not been correctly initialized by its constructor
DateTime::__construct(): Failed to parse time string (1am todax) at position 4 (t): The timezone could not be found in the database
string(3) "UTC"
Warning: DateTimeZone::getName(): The DateTimeZone object has not been correctly initialized by its constructor in %soo_001.php on line %d
bool(false)
The DateTimeZone object has not been correctly initialized by its constructor
DateTimeZone::__construct(): Unknown or bad timezone (GottaFindThisOne)
DONE

View File

@@ -15,7 +15,11 @@ var_dump(IntlDateFormatter::formatObject(new stdclass));
class A extends IntlCalendar {function __construct(){}}
var_dump(IntlDateFormatter::formatObject(new A));
class B extends DateTime {function __construct(){}}
var_dump(IntlDateFormatter::formatObject(new B));
try {
var_dump(IntlDateFormatter::formatObject(new B));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
$cal = IntlCalendar::createInstance();
var_dump(IntlDateFormatter::formatObject($cal, -2));
@@ -34,10 +38,8 @@ bool(false)
Warning: IntlDateFormatter::formatObject(): datefmt_format_object: bad IntlCalendar instance: not initialized properly in %s on line %d
bool(false)
Warning: DateTime::getTimestamp(): The DateTime object has not been correctly initialized by its constructor in %s on line %d
Warning: IntlDateFormatter::formatObject(): datefmt_format_object: error calling ::getTimeStamp() on the object in %s on line %d
bool(false)
The DateTime object has not been correctly initialized by its constructor
Warning: IntlDateFormatter::formatObject(): datefmt_format_object: the date/time format type is invalid in %s on line %d
bool(false)

View File

@@ -199,7 +199,7 @@ function parseClass(Stmt\Class_ $class): ClassInfo {
$className = $class->name->toString();
foreach ($class as $stmt) {
if (!$stmt instanceof Stmt\ClassMethod) {
throw new Exception("Not implemented");
throw new Exception("Not implemented class statement");
}
$funcs[] = parseFunctionLike($className . '_' . $stmt->name->toString(), $stmt);
@@ -230,7 +230,7 @@ function parseStubFile(string $fileName) {
$text = trim($comment->getText());
if (preg_match('/^#if\s+(.+)$/', $text, $matches)) {
if ($cond !== null) {
throw new Exception("Not implemented");
throw new Exception("Not implemented preprocessor directive");
}
$cond = $matches[1];
} else if ($text === '#endif') {
@@ -284,7 +284,11 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
$returnType->toTypeCode(), $returnType->isNullable
);
} else {
throw new Exception("Not implemented");
$code .= sprintf(
"ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_%s, %d, %d, %s, %d)\n",
$funcInfo->name, $funcInfo->return->byRef, $funcInfo->numRequiredArgs,
$returnType->name, $returnType->isNullable
);
}
} else {
$code .= sprintf(