解説
今回のプログラムは、前回の連載でも利用した「date」というファンクションを利用します。dateファンクションは、「今日」の日付以外にも自由な日時を指定して書式を整えることができます。省略できるパラメーター
前回の連載では、dateファンクションには1つのパラメーターを指定していました。しかし、今回のプログラムでは2つのパラメーターが指定されています。実は、ファンクションに指定するパラメーターには省略ができるものと必須のものがあります。次のドキュメントをみてみましょう。
PHP: date - Manual
http://php.net/manual/ja/function.date.php
これをみると、dateには2つのパラメーターが指定できることが分かります。
string date ( string $format [, int $timestamp = time() ] )
しかし、2つ目のパラメーターにはかっこ([])がつけられていて、省略可能である事を示しています。省略した場合、「デフォルト値(標準値)」が指定され、この場合は「今現在の日付」が指定されたことになります。
タイムスタンプという値
では、2つ目のパラメーターに自由な日付を指定するにはどうしたらよいでしょうか。PHPではこれを「タイムスタンプ」という形式で指定するようにされています。タイムスタンプとは、1970年 1月 1日を0秒としそこからの通算秒を数えた数字で、たとえば2013年1月1日 00:00:00のタイムスタンプは、1356966000になります。計算で求めるには閏年なども考慮しなければならないのでかなり面倒ですが、PHPには簡単に知ることができるファンクションが準備されています。
たとえば、今現在のタイムスタンプを知る場合は、次のようなプログラムになります。新しいファイルを作成して確認しましょう。
print(time());
現在のタイムスタンプ
PHP: mktime - Manual
http://jp1.php.net/manual/ja/function.mktime.php
年月日や時間を順番に指定していきます。少し変わった順番なので、気をつけて指定していきます。これを使って、2013/01/01 00:00:00のタイムスタンプを知るには、次のように指定します。
print(mktime(0, 0, 0, 1, 1, 2013));
このファンクションと、dateファンクションを組み合わせれば、次のように自由な日時の書式を整えることができるようになります。
print(date('Y年 n月 j日', mktime(0, 0, 0, 1, 1, 2013)));
dateファンクションで書式を調整
mktimeの特殊な仕様
mktimeファンクションには、少し変わった使い方があります。次のように試してみましょう。print(date('Y年 n月 j日', mktime(0, 0, 0, 1, 1 + 15, 2013)));
パラメーターに計算式を指定しています。すると、自動的に計算をして1月 16日の日付を表示しました。さらに、次のように指定してみましょう。
print(date('Y年 n月 j日', mktime(0, 0, 0, 1, 1 + 35, 2013)));
この場合、普通に計算をしてしまうと1月 36日というおかしな日付になってしまいます。しかし、mktimeファンクションは末日を超えたら、月を進めて正しい日付になるように計算してくれるのです。もちろん、年が超える場合はそれも正しく計算します。
このしくみをうまく利用すると「今日から10日後の日付を指定する」といったことが簡単に行えます。
効率のよいプログラムを作る
では、ここまでのプログラムを応用して、「今日から10日後までの日付を表示する」というプログラムを作成してみましょう。<?php date_default_timezone_set('Asia/Tokyo'); ?> <option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, date('n'), date('j') + 0, date('y')))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, date('n'), date('j') + 0, date('y')))); ?></option> <option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, date('n'), date('j') + 1, date('y')))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, date('n'), date('j') + 1, date('y')))); ?></option> <option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, date('n'), date('j') + 2, date('y')))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, date('n'), date('j') + 2, date('y')))); ?></option> <option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, date('n'), date('j') + 3, date('y')))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, date('n'), date('j') + 3, date('y')))); ?></option> ...
残りは省略しましたが、次の数字の部分を0(今日)から9(10日後)まで変えていきます。
date('j') + 3
これで、確かに正しく動作します。しかし、これではプログラムが非常に長いですし、分かりにくくなってしまっています。少しずつ整理をしてみましょう。
変数で情報を記録しよう
まず気になるのが、何度も出てくる「date」ファンクションです。「mktime」ファンクションのパラメーターに指定するために、現在の日時を取得している部分ですが、同じ結果が得られることが明確なのに、何度も同じファンクションを呼び出すのは効率が悪いです。
そこで、次のように変更します。
<?php date_default_timezone_set('Asia/Tokyo'); $year = date('Y'); $month = date('n'); $day = date('j'); ?> <option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + 1, $year))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + 1, $year))); ?></option> ...
次のプログラムは「変数」という要素を使っています。
$year = date('Y');
現在の年を取得し、それを「$year」という名前の「変数」に記録しています。これは、私たちがワープロソフトなどで作業した結果をファイルに保存しておくのと同じようなもので、ファンクションの結果を一時的に保存しておくための機能です。同じように月を「$month」、日を「$day」という変数に記録しておき増した。
こうしておけば、何度も同じファンクションを呼び出すのを防ぐことができます。記録した変数を利用するときは次のようにして使います。
mktime(0, 0, 0, $month, $day + 1, $year)));
ただし、変数はプログラムが動作している間しか記録されません。Webブラウザを閉じたりすると内容が消えてしまうので気をつけましょう。
繰り返しの制御構造でプログラムをすっきり
次に「<option>」タグの出力部分です。ここでは、次のように「+ ○」という数字部分が違うだけで、ほぼ同じ記述が続きます。<option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + 1, $year))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + 1, $year))); ?></option> <option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + 2, $year))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + 2, $year))); ?></option> ...
このような、同じ事の「繰り返し」を行う場合、プログラムには「繰り返しの制御構造」というものがあり、次のようにすっきりと記述する事ができます。
<?php for ($i=0; $i<10; $i++): ?> <option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + $i, $year))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + $i, $year))); ?></option> <?php endfor; ?>
かなり特殊な書き方なので、改めて詳しく紹介するとして、ここでは次の部分だけを覚えておきましょう。
for ($i=【開始の数字】; $i<【終了の数字+1】; $i++): ... endfor;
この「開始の数字」と「終了の数字」に好きな数字を入れることで、1ずつ加算しながら繰り返してくれます。またその際、今の数字は「$i」という変数で知ることができます。簡単なプログラムで紹介してみましょう。次のプログラムを実行します。
<?php for ($i=1; $i<21; $i++): ?> <p><?php print($i); ?></p> <?php endfor; ?>
こうすると、1から20までの数字が画面に表示されます。数字をそれぞれ変えて、試してみましょう。ちょっと気をつけたいのが、終了の数字が「+1」されることです。20までの場合は「21」と指定します。
こうして、かなりプログラムをすっきりさせることができました。最後の仕上げをしましょう。
次の記述に注目します。
<option value="<?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + $i, $year))); ?>"><?php print(date("n月 j日(D)", mktime(0, 0, 0, $month, $day + $i, $year))); ?></option>
このプログラムには次の記述が2回現れます。
date("n月 j日(D)", mktime(0, 0, 0, $month, $day + $i, $year))
これも、先に紹介した「変数」を使えばすっきりと記述できます。
$this_day = date("n月 j日(D)", mktime(0, 0, 0, $month, $day + $i, $year)); ?> <option value="<?php print($this_day); ?>"><?php print($this_day); ?></option>
これでプログラムの完成です。すっきりして分かりやすいプログラムになりました。
完成したプログラム
プログラムはこのように「そのままでも動作するけど、効率が悪かったり読みにくい」という事が良くあります。そのような場合、より効率的に記述できる方法や、分かりやすく書く方法が必ずあります。
少しずつ知識を身につけながら、キレイなプログラムが書けるようになっていきましょう。