PHP基礎まとめ

未経験からPHP実務半年の駆け出しエンジニアです。
実務と学習で学んだ内容を整理のための記事です。
（学習内容は山浦清透さんの[独学エンジニア](https://dokugaku-engineer.com/course/serverside)というサイトで学んだものをベースにアウトプットしています。エンジニアとしての基礎力を習得したい方にはオススメです。）
PHP初心者の方は良ければ参考にしてください。


## 実務レベルで必要な姿勢（3つ）
1. 自分が理解したコードのみ書くこと<br>
コピペで動いたからOKでは障害や問題等のエラー発生時に対応できない。<br>
2. 読みやすいコードを書く<br>
機能追加や修正は必ずある。その際にパッとみて分かるコードでないと対応できない。<br>
（チーム開発や将来性を見越しているか）
3. 変更しやすいコードを書く<br>
その場限りのコードではなく、機能の変更しやすいコード、拡張性の高いコードを書く。<br>
（運用のこともイメージできているか）<br>
※オブジェクト指向の設計手法が変更・拡張性のしやすいコードに繋がる


## PHP : 変数
### 変数の誕生
技術は課題解決のために作られた。
技術を正しく使いこなすためには、何の解決のためにその技術が誕生したかを知っておくことが大切。
変数の成り立ちを知ることで、変数をより正しく使えるようになることを目指す。<br>


#### 変数の「名前」という概念が誕生する前

名前の概念がない時代、メモリ領域の「数値」を使って識別していた。
（例） 
25番地に本の名前のデータを保存。25番地から本の名前のデータを取り出す。
26番地に著者名のデータを保存。26番地から著者名の名前のデータを取り出す。
 [24番地] [25番地] [26番地] ・・・
何番地に何のデータが保存されているか覚えておかないといけなかった・・・

#### コードを読み書きしやすくするために・・・

これではわかりにくいため、メモリ領域の番地の箇所に'name'のようなラベルを貼ることにした。
（例） 
[24番地('##')] [25番地(<font color="DeepPink">'name'</font>)] [26番地(<font color="DeepSkyBlue">'author'</font>)] ・・・
<font color="DeepPink">'name'</font>に本の名前のデータを保存。<font color="DeepPink">'name'</font>から本の名前のデータを取り出す。
<font color="DeepSkyBlue">'author'</font>に本の名前のデータを保存。<font color="DeepSkyBlue">'author'</font>から本の名前のデータを取り出す。
ラベルを貼ることにより、パッとみて何のデータが保存してあるか分かるようになり、コードの読み書きが格段にしやすくなった。

**変数は、各メモリ領域に値を格納して、それぞれの領域にラベルをつけたもの。**
（変数名は、コードを読みやすくするために誕生しているため、意味の分かりやすい名前をつけることが大切）

### 変数の挙動

```php
$a = 'abc';
$b = $a;
$c = &$a;
$a[0] = 'z'; //$aの1文字目を'z'に変更

echo $a . PHP_EOL; //出力結果:zbc
echo $b . PHP_EOL; //出力結果:abc
echo $c . PHP_EOL; //出力結果:zbc
```

#### リファレンスとは

PHPでは、変数名と変数の中身は別々に存在している。
同じ中身の値に対して、別の複数の名前を持つことができる。

#### 別の名前をつけるには

```php
$c = &$a; // 'abc'の値に、$aと$cという変数名のラベルを貼っている
```
変数の前に＆をつけて代入するとリファレンスが代入される。
リファレンス：別名のこと（あだ名のようなもの）

#### 通常の変数への代入で起こっていること

```php
$b = $a; // $aからコピーした'abc'という値を$bに入れている
```
\$aと\$bの各変数の中身は別物のため、\$aの値を書き換えても\$bの値は変わらない。

#### 通常の変数の代入では「式」が代入されている

\$bには式（\$a）が代入されている。
式：値があるもの全て

### 変数のスコープ

#### 名前をつけただけの変数の問題

名前をつけただけの変数には実は問題がある。
どういう問題があって、どう解決したのかという話。

変数の名前と変数の中身の対応表がプログラム全体で一つだと、名前の衝突が起こる。
（グローバルスコープだけだと名前の衝突が起こる）

#### 名前の衝突を回避しよう

名前の衝突を回避するために作られた概念が「スコープ」である。

ローカルスコープを準備し、名前の有効範囲を限定することで、名前が被らないようにした。
関数の呼び出しごとに専用の対応表に分けた。

#### PHPのスコープ

PHPのスコープにはグローバルスコープとローカルスコープがある。

```php
$num = 0;  //グローバルスコープ（有効範囲がプログラム全体）

function call() {
  $num = 0;  //ローカルスコープ（有効範囲が関数やクラス内）
}
```
注意：グローバルスコープの変数を関数内で使いたい場合は、関数の引数で取る必要がある。
補足：ローカルスコープの有効範囲は言語により異なる。

**変数を定義する時に、名前の有効範囲を意識した上で定義場所を考えるのが重要**

### 定義済み変数
定義済み変数は２種類ある

#### 定義済み変数

実行時にPHPによって自動的に定義される変数

|  変数  |  意味  |
| ---- | ---- |
|  $http_response_header  |  HTTPレスポンスヘッダ配列  |
|  $argc  |  CLIでスクリプトに渡された引数の数  |
|  $argv  |  CLIでスクリプトに渡された引数の配列  |

#### スーパーグローバル変数

どんなスコープからでも使用可能なグローバル変数

|  変数  |  意味  |
| ---- | ---- |
|  $GLOBALS  |  全てのグローバル変数への参照を持つ連想配列  |
|  $_SERVER  |  サーバー情報および実行時の環境情報を持つ連想配列  |
|  $_POST  |  HTTP POSTで渡された変数の連想配列  |
|  $_FILES  |  アップロードされた項目の連想配列  |
|  $_COOKIE  |  HTTPクッキーから渡された変数の連想配列  |
|  $_SESSION  | セッション変数を含む連想配列   |
|  $_REQUEST  |  $_GET、＄_POST、＄＿COOKIEの内容をまとめた連想配列  |
|  $_ENV  |  環境変数の連想配列  |


## PHP : 定数
定数とは、実行中に値を変更できないもの

### なぜ定数が誕生した？
変数だけでは困る時があって誕生したのが、定数である。

下のコードは変数だけを使ってて困るケースの例。
（変数だけだと、変更されたくない値も変更されうる）

```php
$tax = 0.1;
$price = 100 * (1 + $tax);
echo $price . PHP_EOL; // 110

// 別の箇所で気づかずに $tax に別の値を代入してしまったら$priceが正しくない結果になってしまう
$tax = 0.08;
$price = 100 * (1 + $tax);
echo $price . PHP_EOL; // 108
```

### 定数の特徴
- 一度設定されると再定義または未定義にできない
- 変数のスコープに関係なく、どんな場所からでもアクセス可能
- 前に$記号がいらない

### 定数の定義
- constキーワードの後に指定することで定数を定義できる
※トップレベルのスコープで定義する必要がある（関数やif文やループの中では宣言できない、ブロックの外側で宣言する必要があるという意味）

```php
const TAX = 0.1 // 慣習的に常に大文字で定義される（変数と見分けをつけるため）
$price = 100 * (1 + TAX);
echo $price . PHP_EOL; // 110

// 後から定数の値を変更することはできない
TAX = 0.08; // syntax error
$price = 100 * (1 + $tax);
echo $price . PHP_EOL;

const TAX_RATE= 0.1 //　複数単語の場合は _ で繋げる
```

### 定数を使うシーン　主に3つ
1. 値を変更されたくない時
2. 値に意味を持たせたい時
3. 値を一元管理したい時

### 定義済み定数
PHPによって自動的に定義されている定数とマジカル定数の２種類ある

#### 自動的に定義されている定数

（表）代表的なもの

|  定数  |  意味  |
| ---- | ---- |
|  PHP_VERSION  |  現在のPHPのバージョン  |
|  PHP_OS  |  実行しているOS  |
|  E_ERROR  |  重大な実行時エラーのエラー番号  |

https://www.php.net/manual/ja/reserved.constants.php

#### マジカル定数

マジカル定数とは、使われる場所によって自動的に値が変化する定義済み定数のこと。

（表）代表的なもの

|  定数  |  意味  |
| ---- | ---- |
|  \_\_DIR___  |  ファイルのフルパスとファイル名  |
|  \_\_FILE__  |  ファイルの存在するディレクトリ  |
|  \_\_LINE__  |  ファイル上の現在の行番号  |
|  \_\_FUNCTION__  |  関数名  |

https://www.php.net/manual/ja/language.constants.predefined.php

## PHP : 型
### なぜ型は誕生した？
コンピュータの中でデータは1か0（オンかオフ）かで表現されている。
ライトが付くか付かないかのイメージ。
これだけだと何のデータか区別がつかないため、そのデータが「どういう種類の値か」を区別するための情報として「型」が誕生した。

### 2進数
コンピュータはデータを自然数（0〜9）を基盤に扱っている。
この自然数をライトのオンオフでいかに表現できるかを考えた時に、2進数が最適で無駄なく表現できる。
なので、コンピュータ内部ではデータを2進数で取り扱っている。
この2進数の値に対して、どういう種類の値かを示すのが「型」である。

### 型の発展
型はその後、いろんな使われ方をされるように発展していった。

- 仕様としての型で安全性を高めるようになった
関数の引数や戻り値に型を明示することで、プログラムの安全性を高める

- 動的型付けも登場した
型を明示しない動的型付けも誕生した。PHPは動的型付けにより型を自動で判断する。

### PHPの型：①整数

整数には正の整数、ゼロ、負の整数がある

```php
echo gettype(1);   // integer
echo gettype(0);   // integer
echo gettype(-1);  // integer
```
<br>
2進数、8進数、16進数も表現できる

```php
var_dump(0b10);   // int(2)   2進数
var_dump(010);    // int(8)   8進数
var_dump(0x10);   // int(16)  16進数
```
<br>
整数には最大値があり、最大値を超えると浮動小数点型（float）に変換される

```php
var_dump(PHP_INT_MAX);       // int(9223372036854775807)
var_dump(PHP_INT_MAX + 1);   // float(9.223372036854776E+18)
```

### PHPの型：②浮動小数点

浮動小数点とは少数や分数のように、整数で表現できない実数

- 初期化には2種類の方法がある

```php
$float1 = 1.1;
$float2 = 1.1e2;    // 指数表記。1.1*10の2乗
var_dump($float1);  // float(1.1)
var_dump($float2);  // float(110)
```

#### 浮動小数点の扱い方

浮動小数点は精度に限界があるので、扱うときは要注意である。
少数は丸めによる誤差が発生する可能性がある。

- 小数点を使った比較、計算をしないようにする
- 浮動小数点で比較や計算を行うときは任意精度数学関数（BC Math関数）を使う

https://www.php.net/manual/ja/ref.bc.php

### PHPの型：③文字列

#### 文字列の特徴

文字列とは文字が連結されたもの

- 初期化はシングルクォートもしくはダブルクォートを使う
  - シングルクォートは変数を展開しない
  - ダブルクォートは変数を展開する
  - シングルクォートの方が動作処理速度は速い

- 文字列と変数の結合にはドット記号を使うこともできる

```php
$var = 1;
echo '$var years old';    // $var years old
echo "$var years old";    // 1 years old
echo "${var}years old";   // 1years old
echo $var . 'years old';  // 1years old
```

#### エスケープ処理
シングルクォートやダブルクォートを文字として扱うにはエスケープする

```php
echo 'I\'m "Jun 2035"' . PHP_EOL;  //I'm "Jun 2035"
```

#### ヒアドキュメントとNowdoc

複数行になる長い文字列を記載する方法としてヒアドキュメントとNowdocがある

- ヒアドキュメントはダブルクォートで囲んだ文字列として扱う（変数展開される）

```php
$name = 'Jun2035';
$str = <<<EOT
こんにちは。
名前は $name です。
EOT;  // 名前は Jun2035 です。
```

- Nowdocはシングルクォートで囲んだ文字列として扱う（変数展開されない）

```php
$name = 'Jun2035';
$str = <<<'EOT'
こんにちは。
名前は $name です。
EOT;  // 名前は $name です。
```

#### エスケープシーケンス
エスケープシーケンスとはプログラム中で扱いにくい文字を表現するための文字

- 以下はダブルクォートで囲まれた場合、特殊な文字として解釈される

|  エスケープシーケンス  |  意味  |
| ---- | ---- | ---- |
|  \n  |  ラインフィード（改行）  |
|  \r  |  キャリッジリターン（改行）  |
|  \t  |  タブ  |


- 改行コードを実行環境で切り替えたいときはPHP_EOLを使う

|  OS  |  改行コード  |  PHP_EOL  |
| ---- | ---- | ---- |
|  Mac / Linux |  ラインフィード  | \n |
|  Windows |  キャリッジリターン+ラインフィード  | \r\n |

#### 半角文字列と全角文字列の違いに注意

- 全角文字はマルチバイトとしてカウントされるので注意

```php
$str1 = 'abc';
$str2 = 'あいう';
echo strlen($str1);     // 3
echo strlen($str2);     // 9
echo mb_strlen($str2);  // 3
```

- 半角と全角のゆらぎは統一すべし

```php
$name1 = 'ﾑﾗｶﾐﾊﾙｷ';  // 半角
# 半角カタカナは全角カタカナに、全角スペースは半角スペースに、
# 全角英数字は半角英数字に変換する
echo mb_convert_kana($name, 'Kas'); // ムラカミ ハルキ
```

## PHP : 演算子
追記予定

## PHP : 制御構文
追記予定

## PHP : デバックの仕方
追記予定

## オブジェクト指向 : 概念
追記予定

## オブジェクト指向 : クラス
追記予定

## オブジェクト指向 : インターフェイス
追記予定

## オブジェクト指向 : 名前空間
追記予定

## オブジェクト指向 : 例外処理
追記予定