コードが書けるようになってきたのですが、無駄に変数を使っている気がします。どうすれば、変数をうまく扱えるようになるのでしょうか?
変数をうまく扱うには3つのポイントがあります!
- 無駄な変数を削除する
- 変数のスコープ(範囲)を限定する
- 一度だけ書き込む
この記事から得られること
この記事がおすすめの方
- プログラミングが書けるようになってきたものの、書き方が効率的かわからない
- わかりやすい書き方を知りたい
- 効果的な変数の扱いがわからない
まずは結論から!
読みやすい変数の条件は次の3点です。
- 無駄な変数を削除する
- 変数のスコープ(範囲)を限定する
- 一度だけ書き込む
詳しく見ていきましょう!
わかりにくい変数とは何か
わかりやすい変数を書くためには、そもそも「わかりにくい変数とは何か」を知っておくことが需要です。モテたいなら、まずは嫌われない方法を知るのがいいのと同じですね。
わかりにくい変数には3つのケースがあります。
- 変数が多い→把握するのが難しくなる
- 変数のスコープが大きい→把握する時間がかかる
- 変数が頻繁に変更される→現在の値を把握するのが難しくなる
無駄な変数を削除する
変数が多いの対処法はシンプルに削除しましょう!です。具体的にみていきます。
役に立たない中間変数
役に立たない中間変数とは「わざわざ変数にしなくてもわかるよね」と思う変数です。他の場所で再利用もされていないケースです。
例)Laravelでメッセージ送信日を設定する場合
$now = Carbon::now(); $send_message_time = $now;
Carbon::now()を見れば現在日時を取得していることがわかるので、中間変数である$nowを削除します。
修正例)
$send_message_time = Carbon::now();
中間結果を保持する変数
中間結果を保持する変数とは「処理の結果を保持するだけで、最終的には使われない変数」です。
例)
$users = [ ['id' => 1, 'name' => 'hamu'], ['id' => 2, 'name' => 'tanaka'], ['id' => 3, 'name' => 'tack'], ['id' => 4, 'name' => 'sato'], ]; $sample_name = null; foreach ($users as $user) { if ($user['id'] >= 3) { $sample_name = $user['name']; break; } } if (isset($sample_name)) { var_dump("名前は{$sample_name}です。"); } //名前はtackです。
idが3以上になったら名前を取り出して、ループ処理を中断しています。その後名前が存在すれば、出力させています。
$sample_nameに着目すると、該当する名前を保持しているだけです。
結果をそのまま使えるかを考えて、可能な場合は削除してしまいましょう。
修正例)
foreach ($users as $user) { if ($user['id'] >= 3) { var_dump("名前は{$user['name']}です。"); break; } } //名前はtackです。
制御フロー変数
制御フロー変数とは「処理を中断させたり、分岐させたりする判断にのみ使われる変数」です。
例)条件式2に合致する場合、ループを中断したい
$loop_flag = ture; while ('条件式1' && !$loop_flag) { if ('条件式2') { $loop_flag = false; continue; } }
こうした処理は、変数の状態を考えなければならないので、読み手がわかりにくくなります。まずは、制御フロー変数を使わずに済む方法を考え、どうしても制御できない場合のみ使うようにします。
今回のケースでは条件式2に合致する場合は処理を終了すればシンプルに書けそうです。
修正例)
while ('条件式1') { if ('条件式2') { break; } }
変数のスコープを限定する
スコープとは「適用される範囲」です。変数がどこからでも書き換えられる可能性を少なくすることで、バグを減らして、わかりやすい構造になります。
グローバル変数をローカル変数に変更する
グローバル変数とは「どこからでもアクセスできる変数」です。ここではアクセスできる範囲をクラス内に限定した「メンバ変数」で考えてみます。$countがメンバ変数になります。
class Test { private $count; public function count() { $this->count = 200; return $this->calcCount(); } public function calcCount() { return $this->count * 10; } //その他のメソッドは$countを使っていない }
メンバ変数はクラスの中で使えるので、ミニグローバル変数ともいえる存在です。大きなクラスの中では、どのメソッドが変数を更新しているのかわかりにくくなるため、できる限り減らしたほうがいいです。
今回は$countをローカル変数に変更します。
class Test { public function count() { $count = 200; return $this->calcCount($count); } public function calcCount($count) { return $count * 10; } //その他のメソッドに$countは影響を与えない }
ブロックスコープ
ブロックスコープとは「条件式やループの中に定義された変数は、スコープがその中に限定されること」です。JavaScriptの例を見ていきます。
const users = [ {id: 1, name: "hamu"}, {id: 2, name: "tanaka"}, {id: 3, name: "tack"}, {id: 4, name: "sato"} ]; //sample_nameを定義していない users.forEach(user => { if (user.id === 3) { let sample_name = user.name; } }); console.log(sample_name); //sample_name is not defined
「sample_name」は定義されていないよ!というエラーになってしまいました。sample_nameはforEachのループ処理の中で初めて登場します。そのため、ループ処理を抜けたあとで、値を利用しようとしてもスコープがループ内に限定されるため、定義されていないとなってしまいます。
修正例)
const users = [ {id: 1, name: "hamu"}, {id: 2, name: "tanaka"}, {id: 3, name: "tack"}, {id: 4, name: "sato"} ]; //sample_nameを定義 let sample_name = null; users.forEach(user => { if (user.id === 3) { return sample_name = user.name; } }); if (sample_name) { console.log(`名前は${sample_name}です。`); } //名前はtackです。
ループの外側にsample_nameを定義して、ループ内でidが3と一致した場合に値を入れるようにしています。合致するものがない場合はsample_nameがnullになってしまうため、if (sample_name)で値がある場合のみ出力するようにしています。
ちょっと復習
よくよく見ると不要な変数があります。不要な中間変数を身につけたあなたならきっと気づいているはずです!
そうです!sample_nameがいらないですね。再度修正してみます。
users.forEach(user => { if (user.id === 3) { console.log(`名前は${user.name}です。`); } }); //名前はtackです。
かなりシンプルになりました。
$users = [
['id' => 1, 'name' => ' hamu'],
['id' => 2, 'name' => 'tanaka'],
['id' => 3, 'name' => 'tack'],
['id' => 4, 'name' => 'sato'],
];
//$sample_nameを定義していない
foreach ($users as $user) {
if ($user['id'] === 3) {
$sample_name = $user['name'];
break;
}
}
if (isset($sample_name)) {
var_dump("名前は{$sample_name}です。");
}
//名前はtackです。
定数の位置を下げる
定数の位置を下げるとは「必要な直前に定数は書く」ことです。定数を行頭にまとめて書くと、使われるまでに間隔が空き、実際に使われるときに「この定数って何だっけ?」となってしまいます。
定数の位置を下げることで、適用される範囲をより限定し、直感的に理解しやすいようにします。
一度だけ書き込む
変数の値が何度も書き換わると「現在の値が何なのか把握しにくくなります。」可能な限り一度だけ書き込むようにします。javascriptで言えば、constを使って書き換えられない状態をなるべくつくるということです。
参考
今回参考とさせていただいたのは「リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice) 」です。
もっと上手な書き方を知りたいと思った方はぜひご覧いただくといいかと思います!原則を理解していると書き方が変わります!
コメント