在日期相關運算中,「某年某月有幾天」是基礎又關鍵的需求。PHP 內建 cal_days_in_month() 雖方便,但了解其底層邏輯有助於處理特殊情境(如不支援 Calendar 擴充套件的環境、需自訂曆法規則)。本文解析經典的 daysOfMonth() 實作並提供現代化改寫。
public function daysOfMonth($year = NULL, $month = NULL) {
if ($year === NULL) {
$year = $this->getPart('yy');
}
if ($month === NULL) {
$month = $this->getPart('mm');
}
if ($month == 2) {
if (($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0)
$result = 29;
else
$result = 28;
} elseif ($month == 4 || $month == 6 || $month == 9 || $month == 11)
$result = 30;
else
$result = 31;
return $result;
}
格里曆閏年規則:
程式碼中 ($year % 4 == 0 && $year % 100 != 0) || $year % 400 == 0 完美對應此規則。
function getDaysInMonth(int $year, int $month): int {
// 參數驗證
if ($month < 1 || $month > 12) {
throw new InvalidArgumentException('月份必須在 1-12 之間');
}
if ($year < 1 || $year > 9999) {
throw new InvalidArgumentException('年份超出範圍');
}
// 使用內建函數(需 calendar 擴充套件)
if (function_exists('cal_days_in_month')) {
return cal_days_in_month(CAL_GREGORIAN, $month, $year);
}
// 手動實作(相容無擴充套件環境)
$daysInMonth = [1=>31, 3=>31, 4=>30, 5=>31, 6=>30, 7=>31, 8=>31, 9=>30, 10=>31, 11=>30, 12=>31];
if ($month === 2) {
$isLeap = ($year % 4 === 0 && $year % 100 !== 0) || ($year % 400 === 0);
return $isLeap ? 29 : 28;
}
return $daysInMonth[$month];
}
function getDaysInMonthOOP(int $year, int $month): int {
$date = new DateTime("{$year}-{$month}-01");
$date->modify('last day of this month');
return (int)$date->format('d');
}
// 使用範例
echo getDaysInMonthOOP(2024, 2); // 29
echo getDaysInMonthOOP(2023, 2); // 28
| 方法 | 相依性 | 速度 | 推薦場景 |
|---|---|---|---|
cal_days_in_month() | calendar 擴充套件 | 最快 | 高頻呼叫、生產環境 |
DateTime 物件 | 內建 (PHP 5.2+) | 中等 | 物件導向專案、需時區處理 |
| 手動陣列查表 | 零相依 | 快 | 嵌入式/舊版環境、教學用途 |
'08' 時,intval() 會正確轉為 8,但 (int)'08' 在 PHP 8.1+ 可能拋出非標準數字警告