エンジニアYoutuberの山浦清透さんが運営する独学エンジニアの「レッスン4: 読書ログサービスを作ろう②テキスト版」を学習したので、そのアウトプットを実施する。 レッスン4では、以下がタスクとタスクばらしである。
<タスク>
テキスト版(CUI)のアプリケーションを作成する
<タスクばらし>
- 読書ログを表示する
- 読書ログを登録する
- メニュー化し、アプリケーションとして動作する
- 複数の読書ログを表示
読書ログを表示する
表示するデータ
- 書籍名
- 著者名
- 読書状況
- 評価(5点満点の整数)
- 感想
プログラムを書く際のポイントは1つ処理を書いたら、動作確認を実施すること。
ソースコード
<?php
// PHP_EQLは改行を表す。「.」は文字列の連結
echo '書籍名:銀河鉄道の夜' . PHP_EOL;
echo '著者名:宮沢賢治' . PHP_EOL;
echo '読書状況:読了' . PHP_EOL;
echo '評価:5' . PHP_EOL;
echo '感想:ほんとうの幸せとは何だろうかと考えさせられる作品だった。' . PHP_EOL;
実行結果
書籍名:銀河鉄道の夜
著者名:宮沢賢治
読書状況:読了
評価:5
感想:ほんとうの幸せとは何だろうかと考えさせられる作品だった。
読書ログを登録する
<現状>
プログラムの中にデータを記載し、それを出力していた。
<理想>
ユーザーが入力したデータを出力できるようにする。
- 標準入力(standard input)
キーボードから入力した値は、基本的に標準入力に割り当てられる。その標準入力の値を読み取ればタスクを実現できる。 - fgets(変数)
()で指定したものから1行データを取得する
fgets($handle)
$handle:読み取るデータ元
標準入力の値を取得するには以下のようにする。
<?php
fgets(STDIN);
- 変数
現状だと、ユーザーが入力した値をすぐに出力してしまう。
理想はユーザーが入力した値を保持し、後で表示する。そのために変数を用いる。変数のメリットは「あとから使える」「何度も使える」ところ。
※変数の値はコンピュータのメモリに一時的に保存される。
- trim
入力フォームではユーザーが空白をつけて入力してしまうという事象が多く起こるため、その対策をする必要がある。文字列の先頭及び末尾にあるホワイトスペースを取り除ける。
※trimでは全角スペースは削除できない。全角スペースを削除するためには、別の処理が必要らしいが今回は割愛する。
上記のことを活かしてコードを記載すると以下のようになる。
ソースコード
<?php
// 読書ログを登録する
echo '読書ログを登録してください' . PHP_EOL;
echo '書籍名:';
$title = trim(fgets(STDIN));
echo '著者名:';
$author = trim(fgets(STDIN));
echo '読書状況(未読,読んでる,読了):';
$status = trim(fgets(STDIN));
echo '評価(5点満点の整数):';
$score = trim(fgets(STDIN));
echo '感想:';
$summary = trim(fgets(STDIN));
echo '登録が完了しました' . PHP_EOL . PHP_EOL;
// 読書ログを表示する
echo '読書ログを表示します' . PHP_EOL;
echo '書籍名:' . $title . PHP_EOL;
echo '著者名:' . $author . PHP_EOL;
echo '読書状況:' . $status . PHP_EOL;
echo '評価:' . $score . PHP_EOL;
echo '感想:' . $summary . PHP_EOL;
PHPの概要
次のタスクに取り組む前にPHPの基礎文法が必要なため、この章を挟んだ。
-
PHPはHTMLに埋め込んで記述ができる。そのため、コードはタグで囲む。(ただし、終了タグの下に改行があると、誤作動を生む可能性があるため、終了タグは省略する事が多い。)
-
特徴として、簡単に・素早くWebサイトが作れる。一方で、金融システムなどの厳密に作りたいアプリケーションには向いていない。
-
var_dump()
指定した式の型や値を返す -
var_export(変数名)
変数の中身を表示。var_dumpとの違いは値だけ表示する点。var_dumpは型+値で表示する。 -
if文のコツは最初に処理の全体像を記載。処理の中身はコメントで、後で書く。
-
while文で無限ループを起こしたいときは式にtrueを指定する。
-
無限ループを終了させるにはbreakを使う。
-
配列を使うことで、同じ用途の複数の値を1つの変数に格納できる。
-
ラベルを付けた配列を「連想配列」と呼ぶ。
-
配列の基本操作は、初期化→要素の追加→要素へのアクセス
-
PHPの内部では配列と連想配列は区別されていない。キーに数字を使うか、文字列を使うかの違い。
-
配列は同じ種類の値を順序立ててまとめるのに向いている。
-
連想配列は同じグループだが、属性の異なる値をラベルを付けてまとめるのに向いている。
-
配列の全要素をループするときはforeachを使う。
-
関数を使うメリット
1, 名前が付いて読みやすくなる
2, 何回も同じ処理を書かずに済む -
コーディング規約
PSR-1(日本語訳)
PSR-12(日本語訳)
メニュー化し、アプリケーションとして動作する
<現状>
都度登録し、表示される。
<理想>
メニューから登録するか、表示するかを選べるようにする。
-
プログラム実行の基本は逐次実行。上から下に実行する。
-
メニュー化するには
1, ユーザーが入力した数値に応じて処理分岐する
2, 処理を繰り返す
ソースコード
<?php
// while処理に入る前に空文字を変数に入れておかないと、メニューでいきなり2を選択された際に、変数を定義していないよとエラーが起きてしまう。
$title = '';
$author = '';
$status = '';
$score = '';
$summary = '';
// while(true)で無限ループを実現
while (true) {
echo '1. 読書ログを登録' . PHP_EOL;
echo '2. 読書ログを表示' . PHP_EOL;
echo '9. アプリケーションを終了' . PHP_EOL;
echo '番号を選択してください(1,2,9):';
$num = trim(fgets(STDIN));
if ($num === '1') {
echo '読書ログを登録してください' . PHP_EOL;
echo '書籍名:';
$title = trim(fgets(STDIN));
echo '著者名:';
$author = trim(fgets(STDIN));
echo '読書状況(未読,読んでる,読了):';
$status = trim(fgets(STDIN));
echo '評価(5点満点の整数):';
$score = trim(fgets(STDIN));
echo '感想:';
$summary = trim(fgets(STDIN));
echo '登録が完了しました' . PHP_EOL . PHP_EOL;
} elseif ($num === '2') {
echo '登録されている読書ログを表示します' . PHP_EOL;
echo '書籍名:' . $title . PHP_EOL;
echo '著者名:' . $author . PHP_EOL;
echo '読書状況:' . $status . PHP_EOL;
echo '評価:' . $score . PHP_EOL;
echo '感想:' . $summary . PHP_EOL;
} elseif ($num === '9') {
// break;がある時点で繰り返し処理は強制終了となる
break;
}
}
複数の読書ログを表示
<現状>
読書ログを複数登録しようとしても、最後の読書ログしか登録されない。
<理想>
複数の読書ログを表示できるようにする。
複数の読書ログを表示できるようにするためには、配列を用いる。
ソースコード
<?php
<?php
$reviews = [];
while (true) {
echo '1. 読書ログを登録' . PHP_EOL;
echo '2. 読書ログを表示' . PHP_EOL;
echo '9. アプリケーションを終了' . PHP_EOL;
echo '番号を選択してください(1,2,9):';
$num = trim(fgets(STDIN));
if ($num === '1') {
echo '読書ログを登録してください' . PHP_EOL;
echo '書籍名:';
$title = trim(fgets(STDIN));
echo '著者名:';
$author = trim(fgets(STDIN));
echo '読書状況(未読,読んでる,読了):';
$status = trim(fgets(STDIN));
echo '評価(5点満点の整数):';
$score = trim(fgets(STDIN));
echo '感想:';
$summary = trim(fgets(STDIN));
$reviews[] = [
'title' => $title,
'author' => $author,
'status' => $status,
'score' => $score,
'summary' => $summary,
];
echo '登録が完了しました' . PHP_EOL . PHP_EOL;
} elseif ($num === '2') {
echo '登録されている読書ログを表示します' . PHP_EOL;
/**
* ここを修正
*
* 読書ログを収納している配列の全要素に対して表示処理を行う
*/
foreach ($reviews as $review) {
echo '書籍名:' . $review['title'] . PHP_EOL;
echo '著者名:' . $review['author'] . PHP_EOL;
echo '読書状況:' . $review['status'] . PHP_EOL;
echo '評価:' . $review['score'] . PHP_EOL;
echo '感想:' . $review['summary'] . PHP_EOL;
echo '-------------' . PHP_EOL;
}
} elseif ($num === '9') {
break;
}
}
実行結果
1. 読書ログを登録
2. 読書ログを表示
9. アプリケーションを終了
番号を選択してください(1,2,9):2
登録されている読書ログを表示します
書籍名:ナウシカ
著者名:宮崎駿
読書状況:読了
評価:5
感想:映画よりさらに素晴らしい
-------------
書籍名:スラムダンク
著者名:井上雄彦
読書状況:読了
評価:5
感想:人生の書
-------------
1. 読書ログを登録
2. 読書ログを表示
9. アプリケーションを終了
番号を選択してください(1,2,9):
リファクタリング
ソースコード
<?php
function createReview()
{
echo '読書ログを登録してください' . PHP_EOL;
echo '書籍名:';
$title = trim(fgets(STDIN));
echo '著者名:';
$author = trim(fgets(STDIN));
echo '読書状況(未読,読んでる,読了):';
$status = trim(fgets(STDIN));
echo '評価(5点満点の整数):';
$score = trim(fgets(STDIN));
echo '感想:';
$summary = trim(fgets(STDIN));
echo '登録が完了しました' . PHP_EOL . PHP_EOL;
return [
'title' => $title,
'author' => $author,
'status' => $status,
'score' => $score,
'summary' => $summary,
];
}
/**
* ここを追加
*
* 読書ログを一覧表示するので、listReviews と名付けた
*/
function listReviews($reviews)
{
echo '登録されている読書ログを表示します' . PHP_EOL;
foreach ($reviews as $review) {
echo '書籍名:' . $review['title'] . PHP_EOL;
echo '著者名:' . $review['author'] . PHP_EOL;
echo '読書状況:' . $review['status'] . PHP_EOL;
echo '評価:' . $review['score'] . PHP_EOL;
echo '感想:' . $review['summary'] . PHP_EOL;
echo '-------------' . PHP_EOL;
}
}
$reviews = [];
while (true) {
echo '1. 読書ログを登録' . PHP_EOL;
echo '2. 読書ログを表示' . PHP_EOL;
echo '9. アプリケーションを終了' . PHP_EOL;
echo '番号を選択してください(1,2,9):';
$num = trim(fgets(STDIN));
if ($num === '1') {
$reviews[] = createReview();
} elseif ($num === '2') {
/**
* ここを追加
*
* 関数を呼び出す
*/
listReviews($reviews);
} elseif ($num === '9') {
break;
}
}