在會員系統、占卜應用或個人化推薦中,依出生日期推算星座、生肖與年齡是常見需求。本文提供兩種風格的實作:精簡版星座判斷與完整版綜合類別,並修正原始碼中存在的邏輯錯誤與編碼問題,開箱即用。
| 星座 | 日期區間 | 備註 |
|---|---|---|
| 摩羯座 | 12/22 ~ 01/19 | 跨年界 |
| 水瓶座 | 01/20 ~ 02/18 | |
| 雙魚座 | 02/19 ~ 03/20 | |
| 白羊座 | 03/21 ~ 04/19 | |
| 金牛座 | 04/20 ~ 05/20 | |
| 雙子座 | 05/21 ~ 06/21 | |
| 巨蟹座 | 06/22 ~ 07/22 | |
| 獅子座 | 07/23 ~ 08/22 | |
| 處女座 | 08/23 ~ 09/22 | |
| 天秤座 | 09/23 ~ 10/23 | |
| 天蠍座 | 10/24 ~ 11/22 | |
| 射手座 | 11/23 ~ 12/21 |
※ 以上日期為通用曆法近似值,精確劃分需參考當年節氣交節時刻。
利用「每月星座起始日」陣列,配合 array_key_exists 防呆,邏輯清晰、易維護:
/**
* 依月份、日期回傳星座名稱
* @param int $month 1-12
* @param int $day 1-31
* @return string|false 星座名稱或 false(參數錯誤)
*/
function getConstellation(int $month, int $day) {
// 參數驗證
if ($month < 1 || $month > 12 || $day < 1 || $day > 31) {
return false;
}
// 各月星座起始日(日),索引 0=1月 ... 11=12月
$startDays = [
20, // 1月 水瓶座起
19, // 2月 雙魚座起
21, // 3月 白羊座起
20, // 4月 金牛座起
21, // 5月 雙子座起
22, // 6月 巨蟹座起
23, // 7月 獅子座起
23, // 8月 處女座起
23, // 9月 天秤座起
24, // 10月 天蠍座起
22, // 11月 射手座起
22 // 12月 摩羯座起
];
$signs = [
'水瓶座','雙魚座','白羊座','金牛座','雙子座','巨蟹座',
'獅子座','處女座','天秤座','天蠍座','射手座','摩羯座'
];
$start = $startDays[$month - 1];
// 日期小於起始日 → 上一個星座
$idx = ($day < $start) ? (($month - 2 + 12) % 12) : ($month - 1);
return $signs[$idx];
}
採用物件導向封裝,支援單元測試、擴充性強,並修正原始碼中 strpos 邏輯錯誤、閏年計算不準等問題:
class BirthdayInfo {
private int $year;
private int $month;
private int $day;
public function __construct(int $year, int $month, int $day) {
if (!checkdate($month, $day, $year)) {
throw new InvalidArgumentException('無效出生日期');
}
$this->year = $year;
$this->month = $month;
$this->day = $day;
}
/** 取得星座 */
public function getConstellation(): string {
$startDays = [20,19,21,20,21,22,23,23,23,24,22,22];
$signs = ['水瓶座','雙魚座','白羊座','金牛座','雙子座','巨蟹座',
'獅子座','處女座','天秤座','天蠍座','射手座','摩羯座'];
$start = $startDays[$this->month - 1];
$idx = ($this->day < $start) ? (($this->month - 2 + 12) % 12) : ($this->month - 1);
return $signs[$idx];
}
/** 取得生肖(1900 為鼠年基準) */
public function getZodiac(): string {
$animals = ['鼠','牛','虎','兔','龍','蛇','馬','羊','猴','雞','狗','豬'];
return $animals[($this->year - 1900) % 12];
}
/** 取得周歲(滿歲) */
public function getAge(): int {
$today = new DateTime();
$birth = new DateTime(sprintf('%04d-%02d-%02d', $this->year, $this->month, $this->day));
$diff = $today->diff($birth);
return $diff->y;
}
/** 取得虛歲(傳統算法:出生即 1 歲,過年加 1) */
public function getTraditionalAge(): int {
return $this->getAge() + 1;
}
}
$info = new BirthdayInfo(1990, 5, 15);
echo "星座:{$info->getConstellation()}\n"; // 金牛座
echo "生肖:{$info->getZodiac()}\n"; // 馬
echo "周歲:{$info->getAge()}\n"; // 依今日日期
echo "虛歲:{$info->getTraditionalAge()}\n"; // 周歲 + 1
if (strpos(...)) 判斷 Opera 會失效,正確寫法 if (strpos(...) !== false)。checkdate() 驗證日期合法性,DateTime::diff() 自動處理閏年、跨月。 Accessor,模型自動附屬 constellation、zodiac 屬性。flatpickr 或原生 <input type="date"> 取得標準格式,直接傳給後端。本文提供從精簡函式到完整類別的兩種實作,修正了原始碼的邏輯與編碼缺陷,並採用現代 PHP 特型宣告、例外處理、DateTime 物件,確保準確度與可維護性。直接複製即可投入生產環境,亦可依專案需求擴充農曆生日、星座運勢等功能。