【ドットインストール】PHPカレンダーの解説



![PHPカレンダーの完成図](https://qiita-image-store.s3.amazonaws.com/0/62881/6b5d4487-37e3-e157-633a-50913f3bf43d.gif "PHP_calender000.gif")


ドットインストールのレッスン、「[PHPで作る「シンプルカレンダー](http://dotinstall.com/lessons/calendar_php_v2)」 (全12回)」の備忘録です。復習用にお使いください。

設計について勉強したくて、まずは簡単なプログラムを図で表して理解してみようということでこの記事を作成しました。見出しの後ろに書かれている「#数字」は対応レッスンです。レッスン４からの対応となっています。一覧は、続きを読むのクリックして目次を参照して下さい。  

### 今月の1日の曜日を求める #04

参考元：[\#04 必要な情報を取得しよう](http://dotinstall.com/lessons/calendar_php_v2/24004)

今月の最終日を求める場合は`date("t");`だけで求まるみたいです。date関数は第2引数のtimestampを省略すると、現在の時刻が使われます。

以前は次のように3手順でやっていたのが、format文字`t`のおかげで1手順でできるようになったみだいです。

> t フォーマットを知る前の従来のセオリーはこうでした。
>
> 1.  その月の最初の日(1日)を求める
> 2.  それに "+1 month" する
> 3.  それにさらに "-1 day" する
>
> 引用元：
> <cite><a href="http://d.hatena.ne.jp/koyhoge/20120607/date_t">月の最後の日をPHPで簡単に知る方法</a><cite></cite></cite>

準備はここまでで、本題の１日の曜日の求め方ですがちょっと分かりづらいかなと思います。プログラムに慣れていないと、長文になればなるほど、引数に関数が入るほどわかりづらくなります。でも、落ち着いて整理すれば大丈夫です。

```php
// ドットインストール
$youbi = date("w", mktime(0,0,0,date("m",$timeStamp),1,date("Y",$timeStamp)));

// 上のものは次と同じ
今月 = date("m",$timeStamp);
今年 = date("Y",$timeStamp);
$youbi = date("w", 今月, 1, 今年);
```

どうしょうか？こうやって変数に分けてあげれば理解しやすくなったと思います。とりあえず、パフォーマンスやメモリの節約などの問題は置いておきましょう。理解するための備忘録ですので。

それで、結局$youbiのdate()のタイムスタンプは長く見えますけど、「今年/今月/1」のタイムスタンプを動的に作っているということです。

他のdate関数のformat文字は[PHPマニュアル](http://php.net/manual/ja/function.date.php)で確認しましょう。

### 空セルはstr_repateで #05

参考元：[\#05 カレンダーのセルを生成していこう](http://dotinstall.com/lessons/calendar_php_v2/24005)

カレンダーのセルの作り方は以下の通り

1.  週ごとにHTML文字列を作る
2.  1を配列に1週ずつ入れる
3.  配列を展開

レッスン5では上記のステップ１を行います。$weekのイメージは次の通りです。

![図：１ヶ月分のセルが作られるまで](https://qiita-image-store.s3.amazonaws.com/0/62881/11eb3822-30b2-8c33-c878-ca2cf38e37e7.gif "PHP_calendar001.gif")


for文で入られる日付には、曜日が判別できるクラスがついています。

```php
class="youbi_数字"
```

### $weekには1ヶ月分ではなく1週間分のセルが入る #06

日付のセルを作るfor文を拡張していきます。

土曜日と最終日になると、そこで１区切りとして１週間分を$weeksに入れて、$weekはリセットします。なので、レッスン5の時は$weekに１ヶ月分のセルが入りましたが、今回は１週間分しか入りません。

最終日に処理についてですが、`if ($day == $lastDay){処理}`の部分があるから、最後の週も空セルが入り、１週分となります。この部分がなければ、最後の週だけ7日を満たさない場合があります。最終日が土曜日なら問題ないですが。

### 動的リンクの作成 #07-08

[\#07 前月、翌月へのリンクを作ろう](http://dotinstall.com/lessons/calendar_php_v2/24007)

![図：動的リンクの作成](https://qiita-image-store.s3.amazonaws.com/0/62881/e42718a3-4d40-108e-adf0-929df1f268c0.gif "PHP_calendar002.gif")


1日の曜日を求めるdate()を少しいじります。

```php
date("w", mktime(0,0,0,date("m",$timeStamp),1,date("Y",$timeStamp)));
```

これは次のようなことを表しているので、

```php
date("w", mktime(0,0,0,今月,1,今年));
```

前月、翌月リンクともにdate関数のformatを"Y-m"にして、今月の部分を+-1にしてあげればリンクが作られます。

```php
date("Y-m", mktime(0,0,0,今月 +1 or -1 ,1,今年));
```

前月、翌月リンクに挟まれた「今年-今月」の表示はもっと簡単ですね。date()にformat文字を入れるだけです。前述のように、$timestampはあってもなくても、現時刻が使われます。

---

[\#08 URLから年月を取得しよう](http://dotinstall.com/lessons/calendar_php_v2/24008)

```php
$ym = isset($_GET['ym']) ? $_GET['ym'] : date("Y-m");
```

これがないと初めてサイトを訪れた時はURLにパラメータが入っていないので,`$_GET['ym']`の値が取得できないことになります。値自体が生成されていないからです。なので、そのような時のために、デフォルト値の設定ということですね。今回のデフォルト値は現時刻です。

$ymという指定した月のtimeStampを作るために今回はstrototime()を使っています。mktimeとの違いは次のサイトに詳しく載っています。

[date関数を使った非常に簡単な日時表示PHPプログラム](http://rasukaru55.sitemix.jp/jikan.html)

mktimeもstrtotimeもどちらも指定したtimestampを作るのは同じで、指定方法が違います。それと、strtotimeは存在しない日を指定した場合はfalseが返ってくるのと、来月や先月を求めるときに罠があるのに気をつけた方がいいです。

ただ、今回はこのfalseが返ってくるのを利用して、ifで$timeStampを判定し、デフォルト値を現在時刻に設定しています。

### 安全のために入力値はエスケープ処理 #09

[\#09 出力をエスケープしよう](http://dotinstall.com/lessons/calendar_php_v2/24009)

エスケープ処理についてですが、htmlspecialcharsを使わないと入力された値がプログラムとかだと、それが実行されてしまう時があります。例えば、`<script></script>`のようにjavascriptでalertという関数が実行されたりすると、ポップアップといって、いきなり小さなウィンドウが出てきたりします。そういういたずらを防ぐために、htmlspecialcharsを使うわけです。

### オブジェクト指向 #10-12

今回、ドットインストールのPHPカレンダーのレッスンを記事にしようと思った理由はこのオブジェクト指向について少し考えたいことがあったからです。JavaScriptでオブジェクト指向を書いていた時に、どれぐらいのクラスに小分けした方がいいのか？という疑問が出てきたので、PHPカレンダーのレッスンのソースコードを自分なりに考察したいと思います。

**メンバ変数**

1.  $weeks = array();
2.  $timeStamp;

**メソッド**

1.  カレンダーを作る

    * $weeksに生成したHTMLタグを挿入

2.  $weeksのゲットメソッド

    * index.phpで$weeksをforeachで展開する時に使う

3.  来月、先月の文字列を得る(Y-m)

    * リンクのパラメータとして使う(2つのメソッド)

4.  「今年-今月」の文字列を得る

    * カレンダーの月表示

クラスの内容はこんな感じだと思います。ゲットメソッドは$weeksに対してだけですし、必要なものだけを定義すると良いと感じました。柔軟性をということであれもこれも用意する必要はなさそうですね。

このレッスンでは、後からコードをクラス化にしたのですが、始めからオブジェクト指向で書く場合はどう設計すればいいのでしょうか。多分、次のように列挙した機能をメソッドにしていくのだと思います。


![図：PHPカレンダーのデザイン](https://qiita-image-store.s3.amazonaws.com/0/62881/53e9055f-7f92-0a9d-495c-2af9c6cf3f31.gif "PHP_calendar003.gif")
![図：PHPカレンダーの機能を列挙する](https://qiita-image-store.s3.amazonaws.com/0/62881/eca321ce-3b33-c563-24f4-e7eaf89aec4a.gif "PHP_calendar004.gif")


このようにデザインを決めて、あとはデザインに付けていく機能を列挙していけばいいんだと思います。考察といいながら、ただ図を描いただけですが、少しは理解しやすくなったでしょうか？自分の備忘録としては十分なのですが。