PHPエンジニアのための「良いコード」：明日から実践できるヒント集

# PHPエンジニアのための「良いコード」入門：明日から実践できるヒント集

## はじめに

皆さん、こんにちは！この記事は、PHPエンジニアの皆さんに向けて、「良いコードってなんだろう？」というテーマで一緒に考えていくためのものです。

**この記事で目指すこと:**

* 「良いコード」について、みんなで同じイメージを持てるようになること。
* PHPで「良いコード」を書くための、具体的なコツを掴んでもらうこと。
* これからのコードレビューや毎日の開発に、「なるほど！」と思える知識を持ち帰ってもらうこと。

**そもそも、なぜ「良いコード」が大切なのでしょうか？**

いくつか理由がありますが、例えば…

* **将来の自分や仲間が助かる (保守性の向上):** 未来の変更や機能追加がグッと楽になります。バグを見つけて直すときも、スムーズに進められます。
* **スッと頭に入ってくる (可読性の向上):** 他の人がコードを読んだときに「なるほど、こうなってるのか」と理解しやすくなります。もちろん、未来の自分にとっても優しいですよね。
* **一度作れば何度も使える (再利用性の向上):** 同じような処理を何度も書かなくて済むので、開発がスピードアップします。
* **思わぬ落とし穴を減らせる (バグの減少):** 分かりやすいコードは、そもそもバグが入り込みにくいんです。
* **チームでの仕事がもっと楽しくなる (チーム開発の効率化):** 「これってどういう意味だっけ？」といった余計なやり取りが減って、開発がもっとスムーズに進みます。

**PHPにおける「良いコード」を、もし一言で表すとしたら…**

> **「読みやすくて、変更しやすくて、テストもしやすいコード」**

こんなコードを一緒に目指していきましょう！

---

## 1. 良いコードの基本原則

まずは、どんなプログラミング言語にも共通する、「良いコード」を書く上での基本的な考え方から見ていきましょう。

### 可読性 (Readability) - 読みやすさって大事！

コードは、書いている時間よりも読まれている時間の方がずっと長い、と言われています。だからこそ、誰にとっても「分かりやすい！」と思ってもらえるコードを心がけたいですね。

* **名前は体を表す (命名規則):**
    * 変数や関数、クラスの名前は、パッと見て「ああ、これね！」と役割が分かるような名前を付けましょう。
    * PHPの世界には、[PSR-1](https://www.php-fig.org/psr/psr-1/)や[PSR-12](https://www.php-fig.org/psr/psr-12/)といった、みんなが参考にしているコーディングのお作法があります。これらを参考に、チームで名前の付け方を統一できると、さらに読みやすさがアップします。
        * クラス名: `UpperCamelCase` (例: `User`、`OrderController` のように、単語の頭文字を大文字に)
        * メソッド名・関数名: `camelCase` (例: `getUserById`、`calculateTotalPrice` のように、最初の単語は小文字で、以降の単語の頭文字を大文字に)
        * 変数名: こちらも `camelCase` が一般的です (例: `$userName`、`$totalAmount`)
        * 定数: `UPPER_CASE_WITH_UNDERSCORES` (例: `MAX_LOGIN_ATTEMPTS` のように、全部大文字で単語間をアンダースコアでつなぐ)
    * **ちょっと残念な例:**
        ```php
        <?php
        // $x って何だろう…？
        $x = 100;
        // get_data() で何が取れるのかな？
        $data = $this->get_data();

        function proc($p1, $p2) { // proc って何の処理？ p1, p2 は何者？
            // ...
        }
        ?>
        ```
    * **いい感じの例:**
        ```php
        <?php
        // これなら一目でわかる！
        $maxRetryCount = 100;
        $userData = $this->fetchUserData();

        function processPayment(Order $order, PaymentGateway $gateway) { // 支払い処理をするんだな、と分かる
            // ...
        }
        ?>
        ```

* **「なぜ？」を伝えるコメント術 (コメントの重要性):**
    * コードを見ただけでは「うーん、なんでこんな処理があるんだろう？」と悩んでしまうような部分には、コメントでそっとヒントを残してあげましょう。
    * 特に複雑なロジックや、ちょっとトリッキーなアルゴリズムを使っている場所には、コメントがあると読んでいる人が安心できます。
    * **ただし！** コードを読めばすぐに分かるような、当たり前のことを書くのは避けましょう。コメントは、コードの「行間」を読む手助けをするイメージです。
    * **良いコメントの例:**
        ```php
        <?php
        // ユーザーの最終ログイン日時を更新します。
        // これはセキュリティ上、ログインが成功した際には必ず呼び出すようにしています。
        $user->updateLastLoginAt(new DateTimeImmutable());

        /**
         * 指定された商品IDの在庫数を取得します。
         * もし在庫がなければ、0を返します。
         *
         * @param int $productId 商品IDです。
         * @return int 在庫数を返します。
         * @throws InvalidArgumentException 商品IDが正しくない場合に投げられます。
         */
        function getStockQuantity(int $productId): int {
            if ($productId <= 0) {
                throw new InvalidArgumentException('商品IDが正しくないみたいです。');
            }
            // ... 在庫を取ってくる処理 ...
            return $stock;
        }
        ?>
        ```

* **見た目も大事！ (インデントとフォーマット):**
    * インデント（字下げ）やスペース、改行を上手に使って、コードの構造がパッと見て分かるように整えましょう。
    * チームで「こんな風に書こうね」というルールを決めて、[PHP CS Fixer](https://cs.symfony.com/)や[PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer)のようなツールで自動的に整形するのもオススメです。みんなのコードが同じスタイルだと、とっても読みやすくなりますよ。

* **一つのことだけ得意です (関数の凝集度 - Cohesion):**
    * 1つの関数には、1つの明確な役割だけを持たせるように心がけましょう。これを**単一責任の原則 (SRP)** と言ったりします。
    * もし関数が長すぎたり、色々なことをやりすぎているなと感じたら、もっと小さな関数に分けてみるのが良いサインかもしれません。
    * **ちょっと欲張りな例 (色々なことを一つの関数で):**
        ```php
        <?php
        function handleOrder($orderId) {
            // 1. 注文情報をデータベースから取ってきて…
            // 2. 在庫があるか確認して、引き当てて…
            // 3. 支払い処理をして…
            // 4. 注文確認メールを送って…
            // 5. 注文履歴も記録して…
            // …あれもこれも！
        }
        ?>
        ```
    * **スッキリさせた例 (役割ごとに分ける):**
        ```php
        <?php
        function processOrder(int $orderId): bool {
            $order = $this->orderRepository->findById($orderId);
            if (!$order) {
                // エラー処理
                return false;
            }

            if (!$this->inventoryService->checkAndHoldStock($order->getItems())) {
                // 在庫エラー処理
                return false;
            }

            if (!$this->paymentService->processPayment($order->getTotalAmount(), $order->getPaymentMethod())) {
                // 支払いエラー処理
                // (もしかしたら、確保した在庫を元に戻す処理も必要かも)
                return false;
            }

            $this->emailService->sendOrderConfirmationEmail($order);
            $this->orderLogger->logOrder($order);

            return true;
        }
        ?>
        ```

### 保守性 (Maintainability) - 未来の自分が楽をするために

書いたコードは、後から変更したり、バグを直したりすることが必ずあります。そんなとき、「あの時の自分、ありがとう！」と思えるような、メンテナンスしやすいコードを目指しましょう。

* **同じことは繰り返さない (DRY原則 - Don't Repeat Yourself):**
    * 「同じようなコードをあちこちで書いちゃった…」なんて経験はありませんか？DRY原則は、「同じことは繰り返さないでね」というシンプルなルールです。
    * もし同じようなコードを見つけたら、関数やクラスにまとめて、みんなで使えるようにしましょう。そうすれば、もし修正が必要になっても、一箇所直すだけで済むので、直し忘れやバグのリスクをグッと減らせます。
    * **ちょっと残念な例 (同じ割引計算があちこちに…):**
        ```php
        <?php
        function calculateCartTotal(array $items, User $user): float {
            $total = 0;
            foreach ($items as $item) {
                $total += $item->price * $item->quantity;
            }
            // 割引ロジック
            if ($user->isPremiumMember()) {
                $total *= 0.9; // 10%割引
            }
            return $total;
        }

        function calculateShippingCost(Order $order, User $user): float {
            $baseCost = 500;
            // また同じような割引ロジックが…
            if ($user->isPremiumMember()) {
                $baseCost *= 0.9; // 10%割引
            }
            return $baseCost;
        }
        ?>
        ```
    * **スッキリさせた例 (割引ロジックを一つにまとめる):**
        ```php
        <?php
        class DiscountService {
            public function applyDiscount(float $amount, User $user): float {
                if ($user->isPremiumMember()) {
                    return $amount * 0.9; // 10%割引はここだけ！
                }
                return $amount;
            }
        }

        function calculateCartTotal(array $items, User $user, DiscountService $discountService): float {
            $total = 0;
            foreach ($items as $item) {
                $total += $item->price * $item->quantity;
            }
            return $discountService->applyDiscount($total, $user); // まとめた処理を呼び出す
        }

        function calculateShippingCost(Order $order, User $user, DiscountService $discountService): float {
            $baseCost = 500;
            return $discountService->applyDiscount($baseCost, $user); // こちらも呼び出す
        }
        ?>
        ```

* **魔法の数字にサヨナラ (マジックナンバーを避ける):**
    * コードの中にいきなり現れる「2」とか「10」とか、意味の分からない数字（マジックナンバーと呼びます）は、後から見たときに「これって何だっけ？」となりがちです。
    * こういう数字には、ちゃんと意味の分かる名前を付けた定数にしてあげましょう。
    * **ちょっと分かりにくい例:**
        ```php
        <?php
        if ($user->status == 2) { // 「2」ってどういう状態…？
            // ... 承認済みユーザーの処理 ...
        }
        if ($item->type == 1 && $item->stock < 10) { // 「1」や「10」の意味が知りたい！
            // ... 特定のタイプで在庫が少ない場合の処理 ...
        }
        ?>
        ```
    * **分かりやすい例:**
        ```php
        <?php
        define('USER_STATUS_APPROVED', 2); // 「承認済み」ってことね！
        define('ITEM_TYPE_BOOK', 1);       // 「本」のことか！
        define('LOW_STOCK_THRESHOLD', 10); // 在庫が「10個」より少なくなったら、なのね！
        // クラスの中で定数を定義するのも良い方法です
        // class User { const STATUS_APPROVED = 2; }
        // class Item { const TYPE_BOOK = 1; }

        if ($user->status == USER_STATUS_APPROVED) {
            // ... 承認済みユーザーの処理 ...
        }
        if ($item->type == ITEM_TYPE_BOOK && $item->stock < LOW_STOCK_THRESHOLD) {
            // ... 本タイプで在庫が少ない場合の処理 ...
        }
        ?>
        ```

* **早めに帰ってスッキリ！ (早期リターン / Guard Clauses):**
    * 関数の最初に、エラーになる条件や、処理を進めるための前提条件をチェックして、もしダメならすぐに `return` で関数を抜けちゃうテクニックです。
    * これを使うと、if文のネスト（入れ子）が深くなるのを防いで、メインの処理の流れがスッキリと読みやすくなります。
    * **ネストが深くてちょっと読みづらい例:**
        ```php
        <?php
        function processUserData(User $user = null) {
            if ($user !== null) { // まずユーザーがいるかチェックして…
                if ($user->isActive()) { // 次にアクティブかチェックして…
                    if ($user->hasValidEmail()) { // さらにメールアドレスが有効かチェックして…
                        // …やっとメインの処理！
                        return "処理成功";
                    } else {
                        return "無効なメールアドレスです。";
                    }
                } else {
                    return "非アクティブなユーザーです。";
                }
            } else {
                return "ユーザーが指定されていません。";
            }
        }
        ?>
        ```
    * **早期リターンでスッキリした例:**
        ```php
        <?php
        function processUserData(User $user = null): string {
            if ($user === null) { // ユーザーがいなかったら、すぐ帰る！
                return "ユーザーが指定されていません。";
            }
            if (!$user->isActive()) { // アクティブじゃなかったら、すぐ帰る！
                return "非アクティブなユーザーです。";
            }
            if (!$user->hasValidEmail()) { // メールアドレスが無効だったら、すぐ帰る！
                return "無効なメールアドレスです。";
            }

            // ここまで来たら、安心してメインの処理ができる！
            // ... 主処理 ...
            return "処理成功";
        }
        ?>
        ```

### 再利用性 (Reusability) - 賢く使いまわそう！

一度作ったコードは、他の場所でも役立つかもしれません。上手に使いまわせるように意識すると、開発がもっと効率的になります。

* **色々な場面で活躍できるように (関数やクラスの設計):**
    * 関数やクラスを作るとき、「これはこの処理専用！」と決めつけすぎずに、「もしかしたら、あっちでも使えるかも？」と少し視野を広げてみましょう。
    * 引数や設定で少し動きを変えられるようにしておくと、色々な場面で活躍できる便利な部品になります。
* **便利な道具はどんどん使おう (ライブラリやフレームワークの活用):**
    * 日付の計算、インターネットとの通信、データベースの操作など、よくある機能は、すでに誰かが作ってくれた便利なライブラリやフレームワークがたくさんあります。
    * こういうものを積極的に使うことで、「車輪の再発明（すでにあるものをまた作ってしまうこと）」を避けて、開発時間やテストの手間をグッと減らせます。
    * PHPでは、[Composer](https://getcomposer.org/) というツールを使って、色々なライブラリを簡単に管理できます。

---

## 2. PHPで「良いコード」を実践してみよう！

ここからは、PHPの便利な機能を使いながら、どうすればもっと良いコードが書けるか、具体的なテクニックを見ていきましょう。

### 型宣言 (Type Hinting) のススメ (PHP 7以降) - 「これは〇〇型です」と宣言しよう！

関数の引数や返り値に「これは文字列型ですよ」「これは数値型ですよ」と型を宣言しておくと、コードの信頼性がグッと上がって、他の人が読んだときにも分かりやすくなります。

* **引数の型宣言の例:**
    ```php
    <?php
    // PHP 7.0 から使えます
    function greet(string $name, int $age): void { // $nameは文字列、$ageは数値、返り値はなし(void)
        echo "こんにちは、{$name}さん ({$age}歳)。\n";
    }

    greet("山田", 30); // OK!
    // greet(123, "三十路"); // これはダメ！型が違うのでエラーになります (TypeError)
    ?>
    ```
* **返り値の型宣言の例:**
    ```php
    <?php
    // PHP 7.0 から使えます
    function add(int $a, int $b): int { // $aも$bも数値、そして返り値も数値(int)
        return $a + $b;
    }

    $result = add(5, 3); // $result にはちゃんと数値が入ります
    echo $result;
    ?>
    ```
* **「nullかもしれない」も表現できる Nullable型 (PHP 7.1以降):** 型名の前に `?` を付けると、「この値はnullになることもありますよ」と伝えられます。
    ```php
    <?php
    function findUserById(int $userId): ?User { // Userオブジェクトか、nullを返す
        // ... ユーザーを探す処理 ...
        if ($found) {
            return new User(/* ... */);
        }
        return null; // 見つからなかったらnull
    }
    ?>
    ```
* **「どっちの型でもOK！」な Union型 (PHP 8.0以降):** 複数の型を受け入れたいときに便利です。
    ```php
    <?php
    function processInput(int|string $input): void { // 数値(int)か文字列(string)のどちらかを受け取る
        if (is_int($input)) {
            echo "数値: " . $input . "\n";
        } else {
            echo "文字列: " . $input . "\n";
        }
    }
    processInput(123);
    processInput("hello");
    ?>
    ```
* **クラスの持ち物にも型を！プロパティの型宣言 (PHP 7.4以降):**
    ```php
    <?php
    class User {
        public int $id; // IDは数値
        public string $name; // 名前は文字列
        public ?string $email; // メールアドレスは文字列、もしくはnull

        public function __construct(int $id, string $name) {
            $this->id = $id;
            $this->name = $name;
        }
    }
    ?>
    ```
型宣言をしておくと、思わぬバグを早く見つけられたり、エディタが賢くサポートしてくれたり、コード自体が「これはこういうものです」と説明してくれるドキュメントの役割も果たしてくれたりします。良いことずくめですね！

### エラーとの上手な付き合い方 (エラーハンドリング)

プログラムを書いていると、予期せぬエラーはどうしても起こりえます。そんなときでも、プログラムが突然止まってしまわないように、そして何が起きたのかちゃんと把握できるように、エラーと上手く付き合っていく方法を身につけましょう。

* **`try-catch` ブロックでエラーをキャッチ！:** もしかしたらエラーが起きるかもしれない処理を `try` ブロックで囲んで、もしエラーが起きたら `catch` ブロックで捕まえて、よしなに対応します。
    ```php
    <?php
    function divide(int $a, int $b): float {
        if ($b === 0) {
            // 0で割ろうとしたら、特別なエラーを投げる！
            throw new DivisionByZeroError("おっと、0では割れませんよ！");
        }
        return $a / $b;
    }

    try {
        $result = divide(10, 0); // わざとエラーを起こしてみる
        echo "結果: " . $result . "\n";
    } catch (DivisionByZeroError $e) { // 0で割ったときのエラーをキャッチ！
        echo "エラー発生！: " . $e->getMessage() . "\n";
        // ここでログに記録したり、ユーザーに優しいメッセージを出したりする
    } catch (Throwable $e) { // もし他の予期せぬエラーが起きても、ここでキャッチ！
        echo "何か予期せぬエラーが起きました: " . $e->getMessage() . "\n";
    } finally {
        // tryブロックでエラーが起きても起きなくても、ここは必ず実行される
        echo "処理を終わります。\n";
    }
    ?>
    ```
* **エラーログは名探偵の始まり (エラーログの重要性):**
    * エラーが起きたときに、「何が、どこで、どうして起きたのか」という情報をログファイルに残しておくのは、問題解決の第一歩です。
    * PHPにも `error_log()` という関数がありますが、[Monolog](https://github.com/Seldaek/monolog) のような専門のロギングライブラリを使うと、もっと便利にログを管理できます。
* **PHP 8 の賢い助っ人 Nullsafe operator (`?->`):** オブジェクトのプロパティやメソッドを数珠つなぎで呼び出すとき、途中で `null` が出てくるとエラーになってしまいますよね。でも、この `?->` を使うと、途中で `null` があってもエラーにならずに、最終的に `null` を返してくれるんです。`null` かどうかのチェックが何重にもなるのをスッキリ書けます。
    ```php
    <?php
    // 昔ながらの書き方だと、こうなりがち…
    $country = null;
    if ($session !== null) {
        $user = $session->user;
        if ($user !== null) {
            $address = $user->getAddress();
            if ($address !== null) {
                $country = $address->country;
            }
        }
    }

    // Nullsafe operator (PHP 8.0以降) を使うと、こんなにスッキリ！
    $country = $session?->user?->getAddress()?->country;
    // もし $session や $user や $address のどれかが null でも、$country は null になるだけ。エラーにはならない！
    ?>
    ```

### PHPの便利な道具箱 (組み込み関数・標準ライブラリ - SPL)

PHPには、もともとたくさんの便利な関数（組み込み関数）や、SPL (Standard PHP Library) と呼ばれる標準装備のライブラリが用意されています。これらを上手に使うと、コードをもっと短く、そして効率的に書けますよ。

* **配列を自在に操る！ (配列操作関数):**
    * `array_map()`: 配列の全部の要素に、同じ処理をしたいときに。
    * `array_filter()`: 配列の中から、条件に合うものだけを選び出したいときに。
    * `array_reduce()`: 配列の要素を順番に処理して、一つの結果にまとめたいときに。
    * `in_array()`: 配列の中に、探しているものがあるかどうかチェックしたいときに。
    * `array_column()`: 配列の中の配列から、特定のキーの値だけを抜き出したいときに。
    * 例えばこんな感じ:
        ```php
        <?php
        $numbers = [1, 2, 3, 4, 5];
        // 全部2乗する
        $squaredNumbers = array_map(fn($n) => $n * $n, $numbers); // 結果: [1, 4, 9, 16, 25]
        // 偶数だけ取り出す
        $evenNumbers = array_filter($numbers, fn($n) => $n % 2 == 0); // 結果: [2, 4]

        $users = [
            ['id' => 1, 'name' => 'Alice', 'age' => 30],
            ['id' => 2, 'name' => 'Bob', 'age' => 25],
            ['id' => 3, 'name' => 'Charlie', 'age' => 35],
        ];
        // 名前だけ抜き出す
        $userNames = array_column($users, 'name'); // 結果: ['Alice', 'Bob', 'Charlie']
        ?>
        ```
* **文字列もお手の物！ (文字列操作関数):**
    * `strlen()` (長さ)、`strpos()` (位置検索)、`substr()` (一部分取り出し)、`str_replace()` (置換)、`explode()` (分割)、`implode()` (結合)、`trim()` (端の空白除去) などなど、本当にたくさんあります！
    * 日本語のようなマルチバイト文字を扱うときは、`mb_` が頭に付く関数 (例: `mb_strlen()`) を使うのを忘れずに。
* **特別なデータ構造も！ (SPLのデータ構造):**
    * `SplQueue` (順番待ちの列)、`SplStack` (積み重ねるやつ)、`SplHeap` (優先順位付きの山)、`SplFixedArray` (長さが決まってる配列) など、ちょっと特殊なデータの持ち方・扱い方ができる道具も用意されています。これらを使うと、コードがもっと分かりやすくなったり、効率が良くなったりすることがあります。

### Webの安全を守るために (セキュリティに関する考慮)

私たちが作るWebアプリケーションは、たくさんの人が使います。だからこそ、安全に使えるように、セキュリティのこともちゃんと考えておかないといけません。

* **SQLインジェクション「ダメ、ゼッタイ！」:**
    * ユーザーが入力した文字を、そのままSQLというデータベースを操作する命令文に混ぜてしまうと、悪い人にデータベースを勝手に操作されちゃう危険性があります（SQLインジェクション）。
    * これを防ぐには、必ず**プリペアドステートメント**（命令文の「型枠」みたいなもの）を使いましょう。
    * PDOやMySQLiというPHPの機能を使うと、こんな感じで書けます:
        ```php
        <?php
        // PDOを使った例
        // :email や :status が「型枠」の目印
        $stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email AND status = :status");
        // ユーザーが入力したメールアドレスを、安全な形で :email にセット
        $stmt->bindParam(':email', $email_from_user);
        // ステータスは直接値をセット (これも安全)
        $stmt->bindValue(':status', 1);
        $stmt->execute(); // これでデータベースに問い合わせ！
        $user = $stmt->fetch();
        ?>
        ```
* **クロスサイトスクリプティング (XSS) にも気をつけて！:**
    * ユーザーが入力した文字の中に、もし悪意のあるスクリプト（小さなプログラム）が紛れ込んでいて、それをそのまま画面に表示してしまうと、他のユーザーのブラウザでそのスクリプトが実行されてしまうかもしれません（XSS）。
    * これを防ぐには、画面に文字を表示する前に、必ず `htmlspecialchars()` のような関数で、危険な文字を安全な形に変換（エスケープ）しましょう。
    * ```php
        <?php
        $userInput = '<script>alert("XSSだ！");</script>'; // もしこんな入力があったら…
        // 画面に出す前に、ちゃんとエスケープ！
        echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
        // これで画面には「&lt;script&gt;alert(&quot;XSSだ！&quot;);&lt;/script&gt;」と表示されて、スクリプトは実行されない
        ?>
        ```
    * HTMLのどこに表示するか（タグの中なのか、属性の中なのか、JavaScriptの中なのか）によって、適切なエスケープの方法が違うので、そこも注意が必要です。
* **「本当にこの入力で大丈夫？」 (入力値のバリデーション):**
    * ユーザーが入力してくる値は、いつも正しいとは限りません。「これは数字のはずなのに文字が入ってる！」とか「ありえないくらい大きな数字が来た！」なんてことも。
    * だから、ユーザーからの入力は常に「本当にこれで大丈夫かな？」と疑って、期待している形式や範囲に収まっているか、ちゃんとチェック（バリデーション）しましょう。
    * PHPの `filter_var()` という関数や、[Symfony Validator](https://symfony.com/doc/current/validation.html) や [Laravel Validator](https://laravel.com/docs/validation) のような専門のバリデーションライブラリを使うと便利です。

### (ちょっとステップアップ) オブジェクト指向設計の考え方

もし、もっと大きなシステムや複雑なアプリケーションを作ることになったら、オブジェクト指向という考え方や、その設計原則を知っていると、とても役立ちます。

* **SOLID原則って聞いたことある？:**
    * **S**ingle Responsibility Principle (単一責任の原則): 1つのクラスは、1つのことだけに責任を持とうね。
    * **O**pen/Closed Principle (オープン/クローズドの原則): 新しい機能を追加するのは簡単だけど、今あるコードを直さなくてもいいようにしようね。
    * **L**iskov Substitution Principle (リスコフの置換原則): 親クラスの代わりに子クラスを使っても、ちゃんと動くようにしようね。
    * **I**nterface Segregation Principle (インターフェース分離の原則): 使わない機能まで無理やり持たせるのはやめようね。
    * **D**ependency Inversion Principle (依存性逆転の原則): 具体的なものに直接頼るんじゃなくて、もっと抽象的なもの（約束事みたいなもの）に頼るようにしようね。
* もし、LaravelやSymfonyのようなフレームワークを使っているなら、それらがどんな設計の考え方で作られているのかを知るのも、良いコードを書くヒントになりますよ。

---

## 3. 「良いコード」を書くための、日々のちょっとしたヒントと道具たち

毎日コードを書く中で、「良いコード」を意識して、実際に書いていくための、ちょっとしたヒントや便利なツールを紹介しますね。

* **みんなのお手本、コーディング規約 (PSR):**
    * [PHP-FIG](https://www.php-fig.org/) というグループが作っているPSR (PHP Standards Recommendations) は、PHPの世界で「こんな風に書くと良いよね」というお手本みたいなものです。
    * 特に、PSR-1 (基本的な書き方) や PSR-12 (もっと詳しい書き方) をチームで「これを使おう！」と決めておくと、みんなのコードが同じスタイルになって、とっても読みやすくなります。
* **コードの健康診断、静的解析ツール:**
    * コードを実行する前に、間違いや「こうした方が良いかも？」という点を見つけてくれる賢いツールです。型のエラー、隠れたバグ、コーディング規約違反などを、早めに見つける手助けをしてくれます。
    * 代表的なものには、こんなツールがあります:
        * [PHPStan](https://phpstan.org/): 型のチェックやバグ探しが得意です。
        * [Psalm](https://psalm.dev/): PHPStanと同じように、とってもパワフルな解析ツールです。
* **みんなで育てる、コードレビューの文化:**
    * チームのメンバー同士で書いたコードを見せ合って、「ここ良いね！」「ここはこうしたらもっと良くなるかも？」と意見を出し合うのは、とても大切です。
    * バグを早く見つけられるし、お互いの知識も深まるし、コード全体の品質も上がっていきます。お互いを尊重しながら、建設的なフィードバックを送り合えると最高ですね！
* **「来たときよりも美しく」リファクタリングの習慣:**
    * 「ボーイスカウト・ルール」という言葉があって、「キャンプ場を去るときは、来たときよりも綺麗にしてから去ろう」という意味なんですが、これをコードにも応用してみましょう。
    * 新しい機能を追加したり、バグを直したりするときに、ついでに関連する部分のコードを少しだけ読みやすくしたり、小さな問題を直したりするだけでも、長い目で見るとコード全体の質がどんどん良くなっていきます。

---

## まとめ

さて、色々な話をしてきましたが、最後に大切なポイントをもう一度。

* **「良いコード」っていうのは、結局のところ「読みやすくて、変更しやすくて、テストもしやすいコード」なんだなってこと。**
* **基本はやっぱり大事！** 「読みやすさ」「保守しやすさ」「再利用しやすさ」は、いつも頭の片隅に置いておきましょう。
* **PHPならではのテクニックも活用しよう！** 型宣言、上手なエラー処理、便利な組み込み関数、そしてセキュリティのことも忘れずに。
* **日々の積み重ねが力になる！** コーディング規約、静的解析ツール、コードレビュー、そしてリファクタリング。これらを毎日の開発に取り入れて、少しずつレベルアップしていきましょう。

「良いコード」を書くスキルは、一朝一夕で身につくものではありません。毎日コードを書きながら、「もっと良くするにはどうしたらいいかな？」と考え、学び、試していくことが大切です。この記事が、皆さんの「良いコード」への旅の、ちょっとした道しるべになれたら嬉しいです。

##
プロダクトに向き合い、ユーザーとつながる開発を。
ネットネイティブでは、そんなエンジニアを歓迎しています
https://www.wantedly.com/companies/mdpr