【PHPノート】型について

## はじめに
PHPを習得する必要が出てきたので、公式ドキュメントを参考にしながら学習をスタートさせました。
インプットの定着のためのアウトプットとして自分の言葉で書き残していこうと思います📝
　
**筆者レベル感**

- PHPの名前は知ってる
- フレームワークには、Laravelとかがあることは知ってる
- でも実際コードを読んだこと、書いたことは一切ない
    - （→ 学習の第一歩としてProgateと公式の簡易チュートリアルをやりました）
- これまでに触れてきたのはJavaScript, TypeScript, Python

# PHPと型
PHPは動的型付け言語のため、基本的には型定義は不要ですが、型宣言により静的型付けを行うこともできます。
公式ドキュメントに掲載されている型を列挙したのち、後半で各型についての詳細を記載します。
## 基本型
- `null`
- スカラー型
    - `bool`：論理値
    - `int`：整数
    - `float`：浮動小数点数
    - `string`：文字列
- `array`：配列
- `object`：オブジェクト
- `resource`：リソース
- `never`
- `void`
- クラス内の関係を示す相対型（`self`, `parent`, `static`）
- Value（true, false）
- ユーザー定義型
    - `interface`
    - `class`
    - `Enum`：列挙
- callable
## 複合型
- 交差型
- union型
## 型エイリアス
- mixed
- iterable

# それぞれの型について
### `null`
- 意味のある値を持たない
- 未定義、`unset()`された値 = null扱い
### `bool`
- `true` / `false`
- 以下は`bool`で表現すると`false`になる
    ```php3:bool
    false // 純粋なfalse
    0 // 数値のゼロ
    0.0 // floatのゼロ
    -0.0 // floatのゼロ
    "0" // 文字列のゼロ
    "" // 空文字列
    array() // 要素のない配列
    null // そのままnull
    ```
### `int`
- 整数型のこと
- 10進数、2進数、8進数、16進数を表現できる
    ```php3:int
    <?php
     $x = 1234 // 10進数
    
     // 8進数の場合は先頭に0, 0o, 0Oをつける
     $x = 0123 // = 123(8) = 83(10)
     $x = 0o123 // = 123(8) = 83(10)
     $x = 0O123 // = 123(8) = 83(10)
    
     // 16進数の場合は先頭に0xをつける
     $x = 0x1A // = 1A(16) = 26(10)
    
     // 2進数の場合は先頭に0bをつける
     $x = 0b11111111 // = 11111111(2) = 255(10)
    
     // 桁区切りに_を入れることも許容される
     $x = 1_234_567 // = 1,234,567(10)
     $x = 0o12_34 // = 1234(8)
     $x = 0x1A_2B // = 1A2B(16)
     $x = 0b1010_1111 // = 10101111(2)
     ```
     　
- 整数への変換
    - (int) = 型キャスト
    - `intval()` = 呼び出し関数
        ```php3: int
        (int)true // 1
        intval(true) // 1
        
        (int)false // 0
        intval(false) // 0
        
        (int)null // 0
        intval(null) // 0
        
        (int)"3" // 3
        intval("3") // 3
        
        (int)3.14 // 3
        intval(3.14) //3
        
        (int)"3.14" // 3
        intval("3.14") // 3
    
        (int)"3abc" // 3
        intval("3abc") // 3
    
        (int)"abc3" // 0
        intval("acb3") // 0
        ```
### `float`
- 浮動小数点数
- e = E = 10の冪乗（例：e6 = ×10^6）
    ```php3: float
    $a = 1.234; // 普通の小数 1.234
    $b = 1.2e3; // 1.2 × 10^3 = 1200
    $c = 7E-10; // 7 × 10^(-10) = 0.0000000007
    $d = 1_234.567; // 1234.567
    ```
    　
- floatへの変換
    - `(float)` = 型キャスト
    - `floatval()` = 呼び出し関数
        ```php: float
        (float)"3.14" // 3.14
        floatval("3.14") // 3.14
        
        (float)"3.0" // 3.0
        floatval("3.0") // 3.0
        
        (float)"3" // 3.0
        floatval("3") //3.0
        
        (float)3 // 3.0
        floatval(3) // 3.0
        
        (float)true // 1.0
        floatval(true) // 1.0
        
        (float)false // 0.0
        floatval(false) //0/0
        
        (float)"abc" //0.0
        floatval("abc") //0.0
        
        (float)null // 0.0
        floatval(null) // 0.0
        ```
### `string`
- 引用符：
    ```php3: singleQuote
    echo 'Hello, world!';
    // 出力：Hello,world!
    
    echo 'My name is Hitomi.';
    // 出力：My name is Hitomi.
    
    // ' を出力したい時は直前に \ を入れる
    echo 'I\'m learning PHP!';
    // 出力：I'm learning PHP! 
    
    // \ を出力したい時も直前に \ を入れる
    echo 'C:\\Program Files';
    // 出力：C:\Program Files
    
    // 改行やタブなどの特殊文字はそのまま出力
    echo 'This is line 1 \n This is line 2.';
    // 出力：This is line 1 \n This is line 2.
    ```
　
- 二重引用符
    - `\n` : 改行
    - `\r` : 行の先頭に戻る
    - `\t` : タブ
    - `\\` : `\`
    - `\$` : `$`
    - `\"` : `"`
    ```php3:doubleQuote
    echo "Hello\nWorld!"; 
    // 出力：Hello (ここで改行) World!
    
    echo "Tab\tSpace";
    // 出力：Tab    Space
    
    // 変数展開も可能
    $name = "Peco";
    echo "I'm $name!"; 
    // 出力：I'm Peco!
    
    echo "She said \"I'm $name!\".";
    // 出力：She said "I'm Peco!".
    
    $price = 1000;
    echo "price is \$$price.";
    // 出力：price is $1000.
    ```
　
- ヒアドキュメント構文
    - 複数行の文字列を扱える構文
    - 文字列中の変数やエスケープシーケンスの展開が可能
        ```php3:heredoc
        <?php
        $heredoc = <<<EOD
        This is Heredoc.
        This is line 2.
        'EOD' means 'End of Data'.
        EOD;
        
        echo nl2br($heredoc); // nl2br(): 文字列中の改行 \n を <br> に変換する関数
        ```
        ↓ブラウザでの実際の出力
        ![スクリーンショット 2024-11-15 14.51.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827754/1d11725a-1df5-7c86-5781-d22e632ed07b.png)

　
- Nowdoc構文
    - <<< に続く文字列（識別子 / id）をシングルクオートで囲う
    - 文字列中の変数やエスケープシーケンスは展開されない
```php3: nowdoc
<?php
$nowdoc = <<<'EOD'
This is Nowdoc.
This is line 2.
'EOD' means 'End of Data'.
EOD;

echo nl2br($nowdoc); // nl2br(): 文字列中の改行 \n を <br> に変換する関数
```

:::note info
#### **heredoc と nowdocの使い分けは？**
heredocは、文字列中の変数やエスケープシーケンスを展開したい場合に使用。
反対にnowdocでは変数などを展開したくない / 不要の時に使用し、例えばPHPコードやJSONなどを埋め込みたい時に便利。
:::

### `配列`
- `array()`で作成する
- リスト、ハッシュテーブル、辞書、コレクション、スタック、キューなどとしての使用も可能
```php3: array
<?php

// keyは文字列or整数、valueは任意の値
$arr1 = array(
  "key1" => "value1",
  "key2" => "value2",
  "key3" => "value3", // 複数行の時は末尾の,つけておくと○ (後で要素追加しやすい)
);

// keyを省略した形式も可能
// 各要素にアクセスする時はindexを用いる ($arr2[0]など)
$arr2 = array("value1", "value2", "value3"); // 単行の時は末尾の,なしが○（あっても間違いではない）
```
他にも多くのパターンの例が公式に掲載されているので別記事でまとめます📝


### `resource`
- 特別な変数で、外部リソースへのリファレンスを保持
- `is_resource()`：ある変数がリソースなのかどうかを調べる関数
- `get_resource_type()`：変数のリソース型が何かを返す関数
- - リソースの生成、使用、破棄するための色々な関数が存在する（[公式ドキュメントの一覧](https://www.php.net/manual/ja/resource.php)）

### `never`
- 関数が戻ってこないことを示す戻り値の型
    - 該当するのは以下のいずれか
        - exit()がコールされる
        - 例外がスローされる
        - 無限ループに入る
    ```php3: never
    <?php
    // 公式の例をそのまま拝借
    function sayHello(string $name): never {
        echo "Hello, $name";
        exit(); // exit()で関数が終了し、返り値がないため never型
    }
    
    sayHello("John"); // 出力：Hello, John
    ```

### `void`
- 関数が値を返さずに正常終了する場合の戻り値の型
    - その関数には`return`がなく返り値を持たない
- neverとの違い：関数が正常終了するか(void)、正常終了せずに戻らないか(never)
    ```php3:void
    <?php
    function sayHello(string $name): void {
        echo "Hello, $name"; // 値をreturnしないのでvoid型
    }
    
    sayHello("John"); // 出力：Hello, John
    ```

### `クラス内の関係を示す相対型`（`self`, `parent`, `static`）
- クラスの内部でのみ使用できる型
    - `self`：
        - クラス内のメソッドの中で、**そのクラス自身**を指し示すときに使用される
            ```php3:self
            class User {
                private static $count = 0; // 初期値
            
                public function __construct() {
                    self::$count++; // インスタンスが作成されるたびに静的プロパティ$countが1増える
                }
            
                public static function getCount() {
                    return self::$count; // $countの値を返す
                }
            }

            $user1 = new User(); // count = 1
            $user2 = new User(); // count = 2
            echo User::getCount(); // 出力：2
            ```

    - `parent`：
        - **親クラス**を指し、親クラスで定義されたメソッドやプロパティへアクセスする際に使用
    ```php3:parent
    class Animal {
        public function speak() {
            echo "Animal makes a sound.";
        }
    }
    
    // Animalクラスをもとに新たにDogクラスを作成（クラスの継承）
    class Dog extends Animal { 
        public function speak() {
            parent::speak(); // 親クラス（Animalクラス）のspeakメソッドを呼び出す
            echo " Dog barks.";  // 子クラス（Dogクラス）独自の処理を追加で定義
        }
    }
    
    $dog = new Dog();
    $dog->speak(); // 出力: Animal makes a sound. Dog barks. // 親クラスと子クラスで同じ名前のメソッドがある時には子クラスのメソッドが優先される
    ```
    - `static`：
        - 主に静的プロパティや静的メソッドを使用する時に使われる
            - 静的プロパティ：クラス自体から呼び出せるプロパティで、インスタンスを作成せずに使用可能
                ```php3:static
                class Counter {
                    public static $count = 0; // ←静的プロパティ
                    
                    public static function increment() {
                        self::$count++; // 静的プロパティの値を+1
                    }
                }
                
                // クラス自体から直接アクセスして、静的プロパティを変更
                Counter::increment(); // $count = 1
                Counter::increment(); // $count = 2
                
                echo Counter::$count; // 出力: 2
                ```
                　
            - 静的メソッド：クラス自体から呼び出せるメソッドで、インスタンスを作成せずに使用可能
                ```php3:static
                class MathUtility {
                    public static function add($a, $b) {
                        return $a + $b; // 任意の引数の値の合計を返す
                    }
                }
                
                // インスタンスを作成せずにクラス自体から呼び出して使える
                $result = MathUtility::add(5, 3);
                echo $result; // 出力: 8
                ```

### `Value（true, false）`
- 型だけでなく、特定の値そのものを指定する型
    - false：関数の返り値が必ずfalseになる
        ```php3: value_false
        <?php
        function alwaysFalse(): false {
            return false; 
            // もし return true; にしたらエラーになる
        }
        
        $result = alwaysFalse();
        var_dump($result); // 出力: bool(false)
        ```
        　
    - true：関数の返り値が必ずtrueになる
        ```php3: value_true
        <?php
        function alwaysTrue(): true {
            return true; // 正常に動作する
            // もし return false; にしたらエラーになる
        }
        
        $result = alwaysTrue();
        var_dump($result); // 出力: bool(true)
        ```

### `Enum`
- 列挙型
- 決まった値の集合を定義するための型
    ```php3:enum
    <?php
    enum Status {
        case PENDING;
        case IN_PROGRESS;
        case COMPLETED;
    }
    
    // 使用例
    $status = Status::PENDING;
    
    if ($status === Status::PENDING) {
        echo "ステータスは保留中です。"; // 出力: ステータスは保留中です。
    }
    ```

### `callable`
- 引数などとして関数に渡されるコールバック関数を指す型
- ユーザー定義の関数、　組み込み関数、オブジェクトのメソッドやclassのstaticメソッド、無名関数やアロー関数など
- 言語構成と呼ばれる類のものはコールバック関数として指定できない
    - `array()`, `echo`, `empty()`, `eval()`, `exit()`, `isset()`, `list()`, `print`, `unset()`など
```php3: callable
<?php 

// ユーザー定義のコールバック関数例
function my_callback_function() {
    echo 'hello world!';
}

// クラスのstaticメソッド例
class MyClass {
    static function myCallbackMethod() {
        echo 'Hello World!';
    }
}

// ユーザー定義関数など
// 文字列のように記述して渡す
call_user_func('my_callback_function'); 

// classのstaticメソッド
// array('クラス名', 'メソッド名')として渡す
call_user_func(array('MyClass', 'myCallbackMethod')); 

// オブジェクトのメソッド
// array('オブジェクト', 'メソッド名')
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));

// classのstaticメソッドのコール
// 'クラス名::メソッド名'
call_user_func('MyClass::myCallbackMethod');

// 無名関数
call_user_func(function($name) {
    echo "Hello, $name!";
}, "John"); // 出力：Hello, John!

//　クロージャ
// 外部スコープの変数をクロージャ内で使用する時には use($****)で指定
$message = "Welcome";
$closure = function($name) use ($message) { 
  echo "$message, $name!";
}

call_user_func($closure, "Bob"); // 出力：Welcome, Bob!
```

### `複合型`
- あるデータに対して複数の方を組み合わせて指定
    - `union型`：複数の型の中のどれか1つを満たせばOK（`|`, `or`）
    - `交差型`：複数の型すべてを同時に満たす（`&`, `and`）


### `型エイリアス
- ある型に対して別名(エイリアス)を付け、その別名の指定によってその型を使用できる機能のこと
- classやinterfaceなどの型に対して使うことがある
- `mixed型`：
    - あらゆる型を表現可能
    - ある関数が引数に`mixed型`を受け入れる時、どんな型のデータでも渡すことができる
- `iterable型`：
    - 反復可能なデータ構造
    - foreachでループ処理できるものをイメージするとわかりやすい（配列やTraversableインターフェースを実装するオブジェクトなど）
    - 関数の引数として配列やオブジェクトのいずれかを指定したい時などに使用

## 最後に
公式ドキュメントをもとに自分なりに調べたりして解釈したものを掲載していますが、誤認があったり、誤解を与えるような表現があった場合には 大変お手数ですがご指摘をいただけますと幸いです🙏