PHPとJavaScriptの制御構文の差異まとめ


普段の業務では、JavaScriptをガッと書く時と、PHPをガッと書く時が交互に訪れます。

例えば検索して、結果を表示する機能を作るときは
JavaScriptで見た目部分を作る
↓
PHPでサーバサイドを作る
↓
JavaScriptで見た目部分を作る（再）

といったように、交互にやっているので、
制御構文のちょっとした違いがある2つの言語で
「あれ、これってjsの仕様だっけ、PHPの仕様だっけ」となる自分のための差異まとめです。

PHPとJavaScriptの制御構文は似ている。でも同じじゃない！
（※**そもそも言語が違うだろ**というセルフツッコミ）

# 分岐
## if ~ else
**PHPは'elseif'。JavaScriptは'else if'**

ifの条件には当てはまらないが、条件を指定したい時に使う**えるすいふ**。
PHPでは`elseif`がありますが、JavaScriptに`elseif`はありません。

### PHP: elseif
```php:php
if ($score > 80) {
echo "優";
} elseif ($score > 60) { // elseifと1語で書く
echo "良";
} else {
echo "可";
}
```
PHPでも`else if`とすることはできますが、
波括弧ではなく、コロンでif文を書くときには`elseif`と1語にしないとエラーになるので、
日頃から1語で書くようにしたほうがベターですね。

https://www.php.net/manual/ja/control-structures.elseif.php

### JavaScript: else if
JavaScriptでは`else if`とelseとifの間に半角スペースを入れて書く必要があります。

```js:js
if (score > 80) {
  console.log('優');
} else if (score > 60) { // elseifと1語で書くことは出来ない
  console.log('良');
} else {
  console.log('可');
}
```
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/if...else

今回他のプログラミング言語もざっと調べましたが、`else if`と記述する言語のほうが数が多かったです（その他`elif`や`elsif`）。
自分はPHPが一番慣れているので、たまに「あれ？」となる部分です:sweat_smile:

## switch
**PHPは緩やかな比較。JavaScriptは厳密な比較**という違いがあります。

### PHP: switch
厳密な比較したい人なので、
`switch`文でPHPが緩やかな比較しかしないと知ってﾑｷｰｯとなりました。

> switch/case が行うのは、 緩やかな比較 であることに注意しましょう。
[PHP: switch - Manual ](https://www.php.net/manual/ja/control-structures.switch.php)

```php:php
// php
$rank = '1'; // 文字列の1
$prize= '';
switch ($rank) {
  case 1:
   $prize = 'ハワイ旅行';
   break;
  case 2:
   $prize = 'プレステ5';
   break;
  default:
   $prize = '参加賞';
   break;
}
echo $prize; // 緩やかな比較なので、1等ハワイ旅行大当たり
```

### JavaScript: switch
一方、JavaScriptのswitch文は厳密な比較を行います。
>switch 文はまず始めに式を評価します。次に、式が入力式の結果と評価される値が等しい最初の case 節を (厳密等価演算子 === を使用して) 探し、〔......〕
[switch - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/switch)

```js:js
const rank = '1'; // 文字列の1
const prize = (function (rank) {
  switch (rank) {
    case 1:
     return 'ハワイ旅行';
    case 2:
     return 'プレステ5';
    default:
     return '参加賞';
  }
}(rank))
console.log(prize); // 厳密な比較なので、参加賞
```
#### PHPのswitchで厳密な比較を行うには
PHPのswitchで厳密な比較を行うならば、
switch式の値（括弧の箇所）に`true`を入れて、
caseで比較対象を厳密な比較（`===`）を行うことで可能です。

```php:php
$prize= '';
switch (true) {
  case $rank === 1: // 厳密な比較
   $prize = 'ハワイ旅行';
   break;
  case $rank === 2:
   $prize = 'プレステ5';
   break;
  default:
   $prize = '参加賞';
   break;
}
```
（´-`）.｡oO（if文でよくね？って言われそう...）

可読性でifよりswitchを好む方もいますし、
処理速度に差異が出る時もあるようなので、そこは時と場合によるのかなと...。

> switch文では、条件は1度だけ評価され、 その結果が各case文と比較されます。 elseif文では、条件は、再度評価されます。 使用する条件が単純な比較処理よりも複雑な処理を行ったり、 重い繰り返し処理を行う場合、switchの方が より処理が速い可能性があります。
[PHP: switch - Manual ](https://www.php.net/manual/ja/control-structures.switch.php)

#### PHP8から使えるmatchは厳密な比較を行う
PHP8以降を利用しているならば、`match`式を使って厳密な比較が可能です。

>match 式の比較は、 switch 文が行う弱い比較ではなく、 厳密に値を比較(===) します。
[PHP: match - Manual ](https://www.php.net/manual/ja/control-structures.match.php)

```php:php
$rank = '1';
$prize = match ($rank) {
    1       => 'ハワイ旅行',
    2       => 'プレステ5',
    default => '参加賞',
};

echo $prize; // 参加賞
```

なんかJSチックな書き方...!:relaxed:
match式は値を返してくれますが、`return`不要なので、上のコードだと見た目は配列っぽいですね。
まだ実務で利用したことは無いんですが、今後もっと活用できればいいなーと思います。

# 繰り返し
## foreach / forEach

**PHPは'foreach'。breakできる。
JavaScriptは'forEach'。breakできない。**

### PHP: foreach
PHPにおける繰り返し処理は`foreach`で行うことが多いかな、と。
インデックス配列でも、連想配列でも、オブジェクトでもループしてくれる。

```php:php
$numbers = [1, 2, 3, 4, 5];

foreach ($numbers as $number) {
    // 3より大きい場合はループ終了
    if ($number > 3) {
        break;
    }
    echo $number;
}
```
PHPのforeachは`break`できるので、上記の場合は数字が4以上になったらループを抜けます。
実行すると、`123`と出力されます。


### JavaScript: Array.forEach()
PHPのforeachのノリで使おうと思ったら、そのノリでは使えなかった!やつです。
そもそもJavaScriptのforEach()は配列でしか使えないんですよね。

先程PHPのforeachで書いた処理を、PHPのノリで`break`を書くとエラーになります。

```js:js
const numbers = [1, 2, 3, 4, 5];

// エラーになります
numbers.forEach(number => {
  if (number > 3) {
    break; 
  }
  console.log(number);
});
```
```
Uncaught SyntaxError: unlabeled break must be inside loop or switch
```

え？forEach()はループじゃないの？？とこのエラーを初めて見た時は困惑しましたが、MDNの説明を読むと、あくまで「配列の各要素ごとに一度処理を実行するもの」であって、ループではないということなのだろう[^1]な、と。自分はループの定義さえ曖昧だったのだ...と痛感しました。:astonished:
[^1]: PHPベースにJSの説明を行った構造上、JSのArray.forEach()を「繰り返し」のカテゴリで説明をしています

> forEach() メソッドは与えられた関数を、配列の各要素に対して一度ずつ実行します。
[Array.prototype.forEach() - JavaScript | MDN ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)


ループ処理中に条件によってループを止める、という実装もあると思いますが（JavaScriptでそれを行う場合に）`forEach()`は適切ではない:no_good: ということは心に留めておきたいところです。

`forEach()`は最終手段...!

https://qiita.com/diescake/items/70d9b0cbd4e3d5cc6fce

## for / for...of / for...in
プログラミングで最初に出会うかもしれないループのfor文。
PHPもJavaScriptも書き方はほぼ同じです。

### PHP: for

```php:php
for ($i = 0; $i < 10; $i++) {
  echo $i;
}
```
### JavaScript: for

```js:js
for (let i; i < 10; i++) {
  console.log(i);
}
```

---

ここからは、JavaScriptにはあるけど、PHPには無い`for...`です。

### JavaScript: for...of
配列（など）がループする`for...of`

```js:for...of
const alphabets = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

for (const alphabet of alphabets) {
    console.log(alphabet);
}
```

しかし`for...of`でオブジェクトをループしようとすると

```js:for...of
const user = {
    id      : 'test_user',
    address : 'Tokyo',
    age     : 30
};

for (const userInfo of user) {
    console.log(user[userInfo]);
}
```

```
Uncaught TypeError: user is not iterable
```
userは反復可能ではない、とエラーになってしまいました。ぴえん。

### JavaScript: for...in
オブジェクトで繰り返し処理を行う場合には`for...in`があります。

```js:for...in
const user = {
    id      : 'test_user',
    address : 'Tokyo',
    age     : 30
};

for (const userInfo in user) {
    console.log(user[userInfo]); // プロパティが動的なためブラケット記法
}
```

PHPだとfor文が1種類しかないので、JSでは使い分けが必要なんだな～と最初は驚いた記憶があります。

# まとめ

- PHPは`elseif`、JavaScriptは`else if`
- PHPの`switch`は緩やかな比較、JavaScriptは厳密な比較
    - PHP8以降なら`match`で厳密な比較ができる
- PHPの`foreach`はbreakできるが、JavaScriptの`forEach`はできない
- JavaScriptの`for...of`は配列の繰り返し処理、`for...in`はオブジェクトの繰り返し処理

「似た部分はあるけど、細かいところは違う」というのはなかなか気づくのに難しいので、
それぞれの言語ごとに公式文書を確認する癖をつけたいものです！