【PHP実践|実務向け】PHPでカレンダーロジックを自作する際の「ハマりどころ」とクリーンな実装術

導入

Webシステム開発において、予約受付やイベント管理など、カレンダー機能は頻繁に求められる要件の一つです。ライブラリを使えば一瞬ですが、PHPのDateTimeクラスを活用してロジックを理解しておくと、特定の要件(祝日判定や休業日設定など)に応じた柔軟な実装が可能になります。本記事では、カレンダー生成の基礎と、実務でトラブルになりにくい実装方法を解説します。

基礎知識

PHPで日付を扱う際は、DateTimeクラスを利用するのが標準です。
今回利用する重要なメソッドは以下の通りです。
・setDate($year, $month, $day): 日付をセットします。
・format(‘t’): その月が何日まであるか(日数の合計)を取得します。
・format(‘w’): 曜日を数値(0=日, 6=土)で取得します。
これらを使うことで、カレンダーの「開始位置(何曜日から始まるか)」と「終了位置」を動的に算出できます。

実装/解決策

カレンダーを表示する際、最も重要なのは「1日の前の空白」をどう扱うかと、「6行(42マス)」または「5行(35マス)」のグリッドをどう制御するかです。
実務では、HTMLの生成とロジックを分離し、ループ内で日付オブジェクトをインクリメントしていく手法が、バグを防ぐ鍵となります。

サンプルプログラム

以下は、現代のPHP開発でも通用する、可読性を意識したカレンダー生成のサンプルです。

  • 指定月のカレンダーをHTMLで生成する関数
  • /
    function generateCalendar($year, $month) {
    // 初日のDateTimeオブジェクトを作成
    $date = new DateTime(“$year-$month-01”);
    // 月末の日数と、初日の曜日を取得
    $daysInMonth = (int)$date->format(‘t’);
    $firstDayOfWeek = (int)$date->format(‘w’);

    $html = ‘

    ‘;

    // 1. 月の初日までの空白を埋める
    for ($i = 0; $i < $firstDayOfWeek; $i++) { $html .= '

    ‘;
    }

    // 2. 日付を順に表示
    for ($day = 1; $day <= $daysInMonth; $day++) { // 土曜日の終わりで改行するための判定 if (($day + $firstDayOfWeek - 1) % 7 === 0 && $day !== 1) { $html .= '

    ‘;
    }
    $html .= “

    “;
    }

    // 3. 月末以降の余ったセルを埋める(オプション)
    $totalCells = $firstDayOfWeek + $daysInMonth;
    while ($totalCells % 7 !== 0) {
    $html .= ‘

    ‘;
    $totalCells++;
    }

    $html .= ‘

    日 月 火 水 木 金 土
    –
    {$day} –

    ‘;
    return $html;
    }

    // 実行例
    echo generateCalendar(2023, 10);
    ?>

    応用・注意点

    実務でこのコードを扱う際は、以下の点に注意してください。

    1. 月をまたぐ計算の罠
    DateTime::modify(‘+1 day’)などを使用する際、計算結果が予期せぬ月へ飛ぶことがあります。月をまたぐ処理を行う場合は、必ずその月の1日を基準にするよう設計しましょう。

    2. セキュリティと保守性
    今回のようなHTML生成を直接PHPで行うと、複雑な画面(CSSクラスの付与や特定の日の装飾)に対応できなくなります。実務では、ロジック部分で「日付配列」を生成し、表示部分はテンプレートエンジン(Twigなど)に委譲するのがベストプラクティスです。

    3. 曜日判定の国際化
    今回使用した format(‘w’) は英語圏基準です。ロケールに依存した曜日名が必要な場合は、IntlDateFormatterクラスを使用して、環境に合わせた文字列を取得するようにしてください。

    タイトルとURLをコピーしました