実務4年目のWEBエンジニアが「PHP本格入門（上）」を読んで学んだこと 10選

## はじめに

私は**実務4年目のWEB系サーバーサイドエンジニア**です。

普段は**PHP**（CakePHP, Laravel）を使用し、WEBサービスの開発業務を行なっています。

そんな私がなぜ今さら「**PHP本格入門（上）**（以下 本書）」を手に取ったかというと、「自分は基礎ができていないのではないか」という漠然とした不安を持つようになったためです。

私は独学でエンジニアになったので、体系的に開発を学んだわけではありません。

PHPの基本的な構文は理解していますし、関数も使えます。

フレームワークも使えるようになりました。

次のステップとして、より技術力を高めるためにまずは基礎を勉強しなおそうと考えました。

以上、本書を手に取った経緯でした。

それでは、ここから本書を読んで学んだこと（＝これまで知らなかったこと）をお伝えします。

※ この記事は「新人プログラマ応援 - みんなで新人を育てよう！」イベントの参加記事です。
https://qiita.com/official-events/3f21c92121aa125807b4

https://www.amazon.co.jp/PHP本格入門-上-プログラミングとオブジェクト指向の基礎からデータベース連携まで-大家-正登/dp/4297114682/ref=sr_1_4?__mk_ja_JP=カタカナ&crid=32LARYT7Q4J9I&keywords=PHP本格入門&qid=1650109159&sprefix=php本格入門%2Caps%2C204&sr=8-4

----

## 結論

私が本書を読んで学んだことは、以下の10項目です。

**1. echo関数で文字列を列挙する際は「,」でつなぐべき
2. 宇宙船演算子
3. PHPの暗黙的な型変換
4. 「return」＝「return null」
5. 相対パスの起点ははじめに実行されたPHPファイル
6. PHPはオーバーロードが不可能
7. ハッシュ化と暗号化の違い
8. HTML＆PHPの混在コードの美しい記述方法
9. phpDocumentorによるPHPDoc自動生成
10. 否定の否定は肯定**


ここから、1つずつ詳細をみていきましょう。

----

## 1. echo関数で文字列を列挙する際は「,（カンマ）」でつなぐべき

学んだこと1点目は、「**echo関数で文字列を列挙する際は「,（カンマ）」でつなぐべき**」です。

```php:,（カンマ）.（ピリオド）どちらも処理結果は同じ
<?php
    $total = 100;
    echo $total, '円'; // 100円・・・① 推奨
    echo $total. '円'; // 100円・・・② 非推奨
```

上記の①および②は、どちらも同じ処理結果です。

同じ処理結果なのに、なぜ「.（ピリオド）」ではなく「,（カンマ）」でつなぐべきなのでしょうか？

それは、『**,（カンマ）の方が処理コストを低く抑えられるため**』です。

「.（ピリオド）」の場合、「**文字列を結合 → 結合結果を出力**」という二段階の処理が必要です。

対して「,（カンマ）」の場合、「**文字列を出力**」という処理のみを実行します。

「,（カンマ）」を使用すれば、結合する必要がなく、処理コストを低く抑えることができます。

よって、「**echo関数で文字列を列挙する際は「,（カンマ）」でつなぐべき**」であると言えます。

----

## 2. 宇宙船演算子

学んだこと2点目は、「**宇宙船演算子**」です。

https://www.php.net/manual/ja/migration70.new-features.php

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238817/65a3e310-6402-783e-7423-9ed2acb607cb.png)

宇宙船演算子は、主に配列のソート関係の関数と組み合わせて使用されます。

下記のサンプルコードでは、「配列を「age」キーの値の昇順でソートする」という処理を実行しています。

```php:配列を「age」キーの値の昇順でソートする処理
<?php
$people = [
            ['name' => '田中 真', 'age' => 23,],
            ['name' => '吉田 幸枝', 'age' => 33,],
            ['name' => '松村 隆', 'age' => 21,],
            ['name' => 'Mark Mann', 'age' => 43,],
          ];

usort($people, function($value1, $value2) {
    return $value1['age'] <=> $value2['age'];
});

print_r($people);

/* ↓実行結果。年齢の昇順でソートされている。
Array
(
    [0] => Array
        (
            [name] => 松村 隆
            [age] => 21
        )

    [1] => Array
        (
            [name] => 田中 真
            [age] => 23
        )

    [2] => Array
        (
            [name] => 吉田 幸枝
            [age] => 33
        )

    [3] => Array
        (
            [name] => Mark Mann
            [age] => 43
        )
)
*/
```

非常にスマートにソート処理を記述できますね！

機会があれば使ってみたい演算子です。

----

## 3. PHPの暗黙的な型変換

学んだこと3点目は、「PHPの暗黙的な型変換」です。

```php:PHPの暗黙的な型変換
<?php
    if (!$a) {
```

この場合、**変数aは文字列でも数値型でも問題ありません**。

PHPは、自動的に変数の値を論理型に変換してくれます。

これが「**PHPの暗黙的な型変換**」です。

「if (!$a)」の条件式がどう判定されるかを示したのが下記の表です。

|変数$aの値|	if文に入るか|
|----|----|
|$a = ''|	|YES|
|$a = null|	YES|
|$aが未定義|	YES|
|$a = []	|YES (*)|
|$a = [1, 2]|	NO|
|$a = false	|YES|
|$a = true	|NO|
|$a = 1	|NO|
|$a = 0	|YES (*)|
|$a = -1	|NO|
|$a = '1'|	NO|
|$a = '0'|	YES (*)|
|$a = '-1'|	NO|
|$a = 'abc'|	NO|

(*)は曖昧になりやすいポイントで、エンジニアがきちんと認識して制御すべき項目です。

ちなみに、上記の結果は**empty関数の判定結果と同一**です。

「`if (!$a)`」＝「`empty(!$a)`」ということです。

もっと厳格に値を判定したい場合は、「is_null関数」などの関数を使用しましょう。

----

## 4.「return」＝「return null」

学んだこと4点目は、 **「return」＝「return null」** です。

今まで何も考えず「`return null`」と書いてきましたが、「`return`」だけでよかったんですね……！

```php:returnで処理を終了させる例
<?php
    function hoge($a) 
    {
        if ($a <= 0) {
            return;  // return null と同じ
        {
        return $a;
    }
```

----

## 5. 相対パスの起点ははじめに実行されたPHPファイル

学んだこと5点目は、「**相対パスの起点ははじめに実行されたPHPファイル**」です。

例えば、下記のようなディレクトリ構成を想定します。

```:ディレクトリ構成
.
├── files
│   ├── functions1.php
│   └── functions2.php
└── require.php
```
そして、`require.php`の中に以下のような処理を記述したとします。

```php:require.php
<body>
    <?php require_once './files/functions1.php'; ?>
</body>
```

上記処理で、`functions1.php`を呼び出しています。

`functions1.php`では、同じディレクトリ内の`functions2.php`を呼び出しています。

```php:files/functions1.php
<?php require_once './functions2.php'; ?>
```

一見問題なく動作しそうですが、以下の通りエラーとなります。

```:エラーメッセージ
// 実行コマンド： php require.php
// ↓実行結果
Fatal error: Uncaught Error: 
  Failed opening required './functions2.php' 
    (include_path='.:/opt/homebrew/Cellar/php/8.1.3_1/share/php/pear') in
     /Path/to/src/files/functions1.php:1
```

`functions2.php`のrequireでエラーとなっています。

なぜエラーとなるかというと、「**相対パスの起点ははじめに実行されたPHPファイル**」となるからです。

今回のケースでは、はじめに`require.php`を実行しましたので、相対パスはどのファイルにおいても**require.phpを起点に記述する**必要があります。

以上のような予期せぬエラーを引き起こすため、相対パスはあまり用いない方が良いでしょう。

読み込み対象のファイルは、**絶対パスで書くことが推奨**されています。

----

## 6. PHPはオーバーロードが不可能

学んだこと6点目は、「**PHPはオーバーロードが不可能**」です。

スーパークラス（親クラス）の引数または戻り値を変更して同じ名前のメソッドを作ることを「オーバーロード」といいますが、**PHPにおいてオーバーロードは禁止**されています。

以下のコードでは、引数が違う（＝オーバーロード）ためにエラーとなります。

```php:オーバーロードしようとしてエラーとなる例
abstruct class Clock
{
    public function setTime($time)
    {
        // 処理
    }
}

// オーバーロードをしようとしてエラーとなる
class DigitalClock extends($time, $color)
{
    public function setTime($time, $color)
    {
        // 処理
    }
}
```

----

## 7. ハッシュ化と暗号化の違い

学んだこと7点目は、「**ハッシュ化と暗号化の違い**」です。

本書をそのまま引用します。

> ・**ハッシュ化**　→　復元不可能な（非可逆な）文字列に変換すること
> ・**暗号化**　　　→　復元可能な文字列に変換すること

今までこの違いがあやふやでした！

わかりやすく言語化してくれて大変助かりました:pray_tone1:

----

## 8. HTML＆PHPの混在コードの美しい記述方法

学んだこと8点目は、「**HTML＆PHPの混在コードの美しい記述方法**」です。

本書では、以下のルールで記述することを推奨しています。

- PHPタグを、HTMLタグの一種であると解釈してインデントする。
- 制御構文は、波括弧（{}）ではなくif: 〜 endif; のような構文を使う。
- Webページに出力するための変数の準備はHTMLが始まる前におこなっておき、HTML内では出力だけに専念できるようにする。
- 1PHPタグにつき1行を記述する。
- 表示のための加工処理はあらかじめ関数として定義しておき、HTML中では関数をコールするだけにする。
- PHPで変数値以外のデータ（＝HTMLタグ、固定値データ）を出力しない

上記のルールを意識して、`Before` `After`を見てみましょう。

### Before

HTMLとPHPがごちゃごちゃで見づらいです。

```php:Before
<!DOCTYPE html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <h1>空港データの表示</h1>
<?php
$airports = [
        [
            'name ' => '羽田',
            'address' => '東京都大田区',
        ],
        [
            'name ' => '成田',
            'address' => '千葉県成田市',
        ],
    ];
?>
    <p><?= '空港の数：', count($airports); ?></p>
    ＜h3>空港リスト</h3>
    <ul>
<?php
    foreach ($airports as $airport) {
        if (!isset ($airport ['name'])) {
            continue;
        }
        $address = md_strimwidth($airport['address'], 0, 9, "...", "UTF-8");
?>
        <i><?=$airport['name'], '空港'?>: <?=$address?></li>
<?php 
    }
    echo '</ul>';
?>
</body>
</html>
```

### After

すっきりして見やすいコードになりました:raised_hands:

```php:After
<?php
$airports = [
        [
            'name ' => '羽田',
            'address' => '東京都大田区',
        ],
        [
            'name ' => '成田',
            'address' => '千葉県成田市',
        ],
    ];

function cut(string $string, int $len): string
    {
        Swidth = intval($len) * 2 + 1;
        $result = mb_strimwidth($string, 0, $width, "...", "UTF-8");
        return $result;
    }
?>

<!DOCTYPE html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <h1>空港データの表示</h1>
    <p>空港の数：<?= count($airports) ?></p>
    <h3>空港リスト</h3>
    <ul>
        <?php foreach ($airports as $airport): ?>
            <?php if (!isset($airport['name'])): ?>
                <?php continue; ?>
            <?php endif; ?>
            <i><?= $airport['name'] ?>空港: <?= cut($airport['address'], 4) ?></li>
        <?php endforeach; ?>
    </ul>
</body>
</html>
```

HTMLとPHPの混在コードをどう書くかは、**チーム内でルール化**しておくと良いかもしれませんね。

個人的に、上記のルールはしっくりきたので使わせていただこうと思います！

----

## 9. phpDocumentorによるPHPDoc自動生成

学んだこと9点目は、「**phpDocumentorによるPHPDoc自動生成**」です。

https://docs.phpdoc.org/3.0/

phpDocumentor、とても便利そうですね！

試しにインストールしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238817/4a550365-8c88-9bcd-9878-b86d4ca43254.png)

**ブラウザ上でドキュメントを見ることができます！**

これは実務でも活用していきたいです！

----

## 10. 否定の否定は肯定

学んだこと10点目は、「**否定の否定は肯定**」です。

**否定の否定は肯定なのだから、はじめから肯定形を使おう！**

ということを本書では主張しています。

（当たり前のことですみません）

プログラミングをする上で忘れてはいけない考え方だと感じました。

### Bad

```php:否定の否定の例
// 否定の否定
public function isNotConnected(): bool
```

### Good!

```php:肯定形に修正した例
// 肯定形にする
public function hasConnected(): bool
```

肯定形の方がより使用者に優しいメソッドだと予想できますね！

----

## おわりに

以上、「**実務4年目のWEBエンジニアが「PHP本格入門（上）」を読んで学んだこと 10選**」でした。

PHPの基礎を学ぶのに、本書はとてもためになると感じました。

もしご興味ありましたら、ぜひお手に取ってみてください！

https://www.amazon.co.jp/PHP本格入門-上-プログラミングとオブジェクト指向の基礎からデータベース連携まで-大家-正登/dp/4297114682/ref=sr_1_4?__mk_ja_JP=カタカナ&crid=32LARYT7Q4J9I&keywords=PHP本格入門&qid=1650109159&sprefix=php本格入門%2Caps%2C204&sr=8-4