パーソナルメンターサービスのMENTA経由でご契約いただいているメンティーさんに、
プログラミング言語『PHP』の課題を出してみました。
せっかくなのでブログにも残しておく事にします。
PHPで関数をつくってみた (修正前)
今回のお題です。
- PHPで自動販売機の関数をつくってみてください。
- 引数・・お金と文字
- 戻り値・・お釣り、買った商品名。お金が足りなかったらお金が足りないと表示
- 飲み物の種類はなんでもok
- 飲み物の情報を持った連想配列をつくる
お題の意図としては、
- 関数・条件分岐・連想配列を取り入れつつ読みやすいコードがつくれるか
になります。
こちらがメンティーさんから届いたコードです。
<?php
// 3. 自動販売機の関数を作ってください。
// 引数・・数字(お金)と文字(ジュースの種類)
// 戻り値・・おつり、買った商品。お金が足りなかったらお金足りないと表示
// (ジュースの種類はなんでもok、コーラ、炭酸水など)
// (ジュースの情報を持った連想配列をつくる)
//自動販売機の関数
function buyDrink($num, $name)
{
//ジュースの情報を持った連想配列
$juices = [
[
'name' => '三ツ矢サイダー',
'price' => 120,
],
[
'name' => 'コーラ',
'price' => 120,
]
];
foreach ($juices as $juice) {
//戻り値 お金が足りた場合 買った商品
if (in_array($num, $juice) && in_array($name, $juice)) {
return '買った商品は' . $name . 'です。';
//戻り値 おつりがでた場合 おつりと買った商品
} else if ($num > $juice['price'] && in_array($name, $juice)) {
$diff = $num - $juice['price'];
return "お釣りは{$diff}円です。買った商品は{$name}です。";
//戻り値 お金が足りなかった場合 お金が足りないと表示
} else if ($num < $juice['price'] && in_array($name, $juice)) {
$diff = abs($num - $juice['price']);
return "お金が{$diff}円たりません。";
}
}
return '正しい商品を選択してください';
}
echo buyDrink(120, '三ツ矢サイダー');
echo '<hr>';
echo buyDrink(120, 'コーラ');
echo '<hr>';
echo buyDrink(150, 'コーラ');
echo '<hr>';
echo buyDrink(100, '三ツ矢サイダー');
echo '<hr>';
echo buyDrink(100, '三ツ矢');
echo '<hr>';
処理としては動いてはいるんですが、
読みやすいかと言われたら、なかなか読みづらいですよね。
本人からも、「まだ関数の作り方がうまくいっていない、アドバイスが欲しい。」と連絡がありました。
実際にコードを書いてもらうと、どのあたりまでわかっていて、どこが怪しいか、というのがわかるので、第3者にコードを見てもらうというのは大事ですよね。
プログラミングで関数をつくるコツ
関数作成の考え方ですが、ざっくりいうとこうなるかなと考えています。
- (処理の)流れを考える (フローチャート的な)
- (処理を)できるだけ細かく分ける
- (処理を)できるだけわかりやすくする
1つ目(処理の流れ)は、今回は、
// 1. 商品を探す
// 2. 商品がなければないと返答
// 3. 商品があれば金額計算 お釣り返すかお金が足りないと連絡
と先にコメントを書いて、その下にコードを書いていきました。
2つ目(細かく分ける)は、
商品の情報を連想配列で持たせているので、
商品があるかどうか判断できるフラグを1つつくっています。
(trueかfalseのフラグをつくるようにするとわかりやすくなると思います。)
3つ目(わかりやすくする)は、
else if などが増えるほど読み解くのもややこしくなり、バグも入りやすくなるので、
できるだけelseは使わないように意識してコードを書いていくといいかなと思います。
( 最後1回だけelse描いてますが、elseの出番はこれくらいに抑えたいです)
PHPで関数をつくってみた (修正後)
上のアドバイスを反映させた関数が下記になります。
<?php
//自動販売機の関数
function buyDrink($price, $name)
{
//ジュースの情報を持った連想配列
$juices = [
[
'name' => '三ツ矢サイダー',
'price' => 120,
],
[
'name' => 'コーラ',
'price' => 150,
]
];
// 1. 商品を探す
// 商品有無チェックのフラグ
// 商品番号
$isExisted = false;
$itemNumber = '';
foreach($juices as $key => $juice){
if($juice['name'] === $name){
$isExisted = true;
$itemNumber = $key;
}
}
// 2. 商品がなければないと返答
if($isExisted = false){ return '商品がありません'; }
// 3. 商品があれば金額計算 お釣り返すかお金が足りないと連絡
if($isExisted = true){
if($price >= $juices[$itemNumber]['price'] ){
$change = $price - $juices[$itemNumber]['price'];
return '商品は' . $name . ', お釣りは' . $change .'円です';
} else {
return 'お金が足りないよ';
}
}
}
echo buyDrink(120, '三ツ矢サイダー');
echo '<br>';
echo buyDrink(160, 'コーラ');
echo '<br>';
echo buyDrink(140, 'コーラ');
変更前と比べると大分読みやすくなったんじゃないかなと思います。
もうちょい綺麗に書けそうな気もしますが、これくらいのコードになっていると第三者からも読みやすいんじゃないかなと。(コメントでアノテーション書くとか引数に型書いた方がいいとか細かく言えばもっといろいろありますけども)
データをどこにおくか問題
その後メンティの方とSlackでやりとりしていて、
連想配列をどこにおくかという話になったので書いておくと、
データの置き場所は4種類くらい考えられます。
- 関数の中
- 関数の外(グローバル)
- 関数の外(別ファイルや別クラス)
- データベース
今回はファイル1つで処理も少ないので関数の中にまとめてますが、
例えばジュースの在庫管理や在庫履歴など、他の機能もつけていくと、どの方法がいいか検討必要になってきますね。
(在庫管理あるならデータベース使った方がいいと思う)
という事で、ファイルの規模や仕様次第でどうとでも変わるんですが、今回に関してはファイル1つだし、処理少ないし、関数にまとめてもいいかなというところで。
プログラミング関数のレビューをしてみて
progateやドットインストール、Udemyもそうですが、
動画を見て真似てると、それなりに書けるようになってはくるんですが、
少し応用編というか組み合わせ、実践的になってくると初めの頃は難しいのかなと思います。
実際にコードを書いてもらって、個別に添削してもらう事でググッとパワーアップできるので、
もしプログラミングの関数などアドバイスが欲しいという場合は、
ぜひお気軽にご連絡くださいませ。
この記事へのコメントはありません。