1. shinkuFencer
Changes in body
Source | HTML | Preview
@@ -1,178 +1,215 @@
正常系は上手く動くし問題ない!と思ってもケースによっては危なかったり
あんまりよくない書き方ってあると思います。
そういうような控えたほうががいいような書き方をケース別にまとめたものです。
まばらには書かれているんですが、一つの場所にはまとまってないのでメモがてら。
## ==での比較
違う言語から戻ってくると間違って書いてしまいがちな判定。
+
+### 問題点
+
+`==` の場合は 型の相互変換をかけてから比較するので
+意図しない比較が行われる可能性がある
+[PHP: 型の相互変換 \- Manual](http://php.net/manual/ja/language.types.type-juggling.php)
+
+### コード例と解説
以下のようなコードがあるとします。
```php
if ($target == 1) {
echo 'this is 1';
}
```
もちろん `target = 1;` のときにも通るのですが
`==` だと1以外のものでも判定が `true` になってしまうものが結構あります。
`true` になってしまう例としては以下。
```php
$target = "1";
$target = true;
$target = "1aaa";
// 上記はすべてtrueになる
```
-すべて暗黙の型変換が原因(参考リンク参照)
-暗黙の型変換を頼りたい場面(そんなにないと思いますが)以外は
+すべて型の相互変換(暗黙の型変換[^1])が原因
+型の相互変換を頼りたい場面(そんなにないと思いますが)以外は
`===` を使った方がいいと思います。
+
## 空文字判定としてのempty
-以下のような場合。
-
+### 問題点
+
+`empty` は文字通り空を判定するが
+空と定義する範囲が広いので、思わぬものも `空` と認識されてしまう。
+
+### コード例と解説
+
```php
// $targetが空文字の場合はデフォルト値を入れる
if (empty($target)) {
$target = "default";
}
```
一見大丈夫そうに見えるのですが
`empty()` は 空文字以外にも色々 `true` 扱いしてくれるので
範囲が広くて危険です。
> [PHP: empty \- Manual](http://php.net/manual/ja/function.empty.php)
>次のような値は空であるとみなされます。
"" (空文字列)
0 (整数 の 0)
0.0 (浮動小数点数の 0)
"0" (文字列 の 0)
NULL
FALSE
array() (空の配列)
$var; (変数が宣言されているが、値が設定されていない)
0という文字も空扱いになってしまいます。
そのため、「何も文字が入って来ないときは変わりに文字を代入」のような処理の場合は
空白比較をしたほうが良いです。
```php:改訂例
if ($target === "") {
$target = "default";
}
```
## 配列の宣言なしでの代入
+### 問題点
+
+変数に対して記述のしかたと代入する場所の状態によって
+よしなに配列を自動で生成してくれるが
+既に何か入っていると代入が失敗したりするので
+思わぬバグを生む可能性がある。
+
+### コード例と解説
+
下記のような処理があるとする。
```php
$array = [];
$array['flower'] = "yeah";
$array['star'][1] = "hoge";
$array['star'][2] = "hoge";
```
-`$array['star'] = []` ってわざわざ宣言しなくても
+`$array['star'] = []` わざわざ宣言しなくても
配列ができあがってくれます。
簡単な処理なら便利なのですが
以下のようになってしまうと値が入らなくなってしまいます。
```php
$array = [];
$array['flower'] = "yeah";
// string型のものを入れる
$array['star'] = "string!";
// すでにstringが入っているので代入できない
$array['star'][1] = "hoge";
$array['star'][2] = "hoge";
```
そのため、できるだけ配列をネストしたりする場合は
空配列を宣言しておいたほうが明示的でわかりやすくなるので安心です。
```php:改訂例
$array = [];
$array['flower'] = "yeah";
// string型のものを入れる
$array['star'] = "string!";
// 新たに配列を代入したい場合は以下
$insertArray = [];
$insertArray[1] = "hoge";
$insertArray[2] = "hoge";
$array['star'] = $insertArray;
```
## arrayを引数とするfunction
-以下のような処理があるとする
+### 問題点
+
+`array`の変数を引数にして`function`を作ると
+本来必要のない情報が渡ったり、配列の状態を細かく判定する必要が出てくるので
+本来やりたい処理とは異なる部分に気を使う必要が出て来る
+
+### コード例と解説
+
+以下のような処理があるとする
```php
public function jsonToProfileText($json)
{
// jsonをデコードしてarrayに
$student = json_decode($json, true);
return $this->createProfileText($student);
}
private function createProfileText($student)
{
$name = $student['name'];
$age = $student['age'];
return "My Name is" . $name . ", " . $age . " years old.";
}
```
arrayにすべてのデータが入ってて、そのまま渡したほうが楽なので引きまわしてます。
-この場合、配列なので想定キーに文字列が入っていない場合があります。
-その場合配列の中にキーがるかまで気にしないといけないので
+この場合、配列なので取り出したいキー(上記の場合だと `name` や `age`)が
+なかったりする場合があります。
+
+その場合配列の中にキーが存在するかまで気にしないといけないので
もし厳重にチェックしたい場合は配列のキーチェックなどが必要になります。
+
でも `createProfileText` は文章を作る処理なのにキーを気にするのは
文章作るという作業の範疇を超えている気もします。
-渡してあげる文字を気にするのはどちらかと言うと呼び出し側なので
+渡してあげる文字があるかを気にするのはどちらかと言うと呼び出し側なので
呼び出し側で見てあげて、文章を作る方には必要な要素だけ渡してあげると
`createProfileText` は文章をつくることに集中できます。
上記のことを踏まえて直すと以下のようになります。
```php
public function jsonToProfileText($json)
{
$student = json_decode($json, true);
+ // 必要であればここで $student['name'] と $student['age'] の状態を確認する
return $this->createProfileText(
$student['name'],
$student['age']
);
}
private function createProfileText($name, $age)
{
return "My Name is" . $name . ", " . $age . " years old.";
}
```
こちらに関してはケースバイケースなので
必ず分解してパラメータを渡そう!ってことではないですが
考え方として頭に入れておくと空チェックなどが集約できますし
見通しがよくなることがあります。
## 参考URL
### まとめる上で参考したページ
* [PHPの文字列比較で気をつけるべきこと – 暗黙の型変換 \- EC studio 技術ブログ](http://techblog.ecstudio.jp/tech-tips/php-string-compare.html)
* [PHP isset, empty, is\_null の違い早見表 \- Qiita](http://qiita.com/shinichi-takii/items/00aed26f96cf6bb3fe62)
### その他有用Tips
* [isset\(\)と\!is\_null\(\)の値は常に等しいか \- cnrdの日記](http://d.hatena.ne.jp/cnrd/20091127/1259235755)
* [PHP初心者が仕事で躓いた4つの罠 \- pixiv inside](http://inside.pixiv.net/entry/2015/12/02/203958)
+
+[^1]: 型の相互変換が正しい呼び方。ありがちなケースに関しては参考ページにも記載している[こちら](http://techblog.ecstudio.jp/tech-tips/php-string-compare.html)がわかりやすいです。