PHPの名前空間を理解する

##結論


 * クラスや関数名の衝突を防ぐために名前空間は存在する。
 * 名前空間を使用することで違う名前空間同士であれば同じ名前のクラス名や関数名を定義できる。

##名前空間について


>名前空間とは何でしょう? 広義の「名前空間」とは、項目をカプセル化するもののことです。

PHPでは**同じ名前の関数名を使うことはできません。**もし関数名を定義して呼び出すとエラーが起きます。同じ関数名`greet`を2つのファイルに定義して呼び出すとエラーが起きます。

```php:japanese.php
<?php

function greet() {
    return 'こんにちは';
}
```

```php:english.php
<?php

function greet() {
    return 'こんにちは';
}
```

```php:greet.php
<?php
require_once 'japan.php';
require_once 'usa.php';

echo greet();
```

```結果
PHP Fatal error:  Cannot redeclare greet()
```

こういったことを避けるために名前空間が存在します。
もし名前空間を使わないと

 * 関数名の衝突を避けるために長い関数名を定義しなければならなくなる
 * また複数人でコードを書いたときに名前が衝突する恐れがある

といったことが起きてしまいかねません。
こういったことを避けるために名前空間を使います。

また

 * 定数（constで定義）
 * 関数
 * クラス
 * インターフェイス
 
 これらも同じ名前を使い回すことができないので、名前の衝突を避けるためにも名前空間を使います。主にクラス名の名前の衝突を避けるために使われます。**いわば名前空間は入れ物のようなイメージになり名前空間の異なるものはお互いの影響を受けない**ことになります。

##名前空間の定義
名前空間を定義するにはキーワード`namespace`を使用します。
`namespace`は必ずコードの先頭に書きます。PHP以外の文（HTML）なども`namespace`よりも前に書くことができません。
`namespace`よりも前に書くことができるコードは`declear`のみなので注意して下さい。


```php:namespaceより前にHTMLを書いた場合 
<html>
<?php
namespace MyProject; // fatal error - namespace must be the first statement in the script
?>
```

##名前空間内の関数などを呼び出す方法
ディレクトリやファイルを呼び出すように名前空間名のあとに`\(バックスラッシュ)`のあとに関数名を続けることで呼び出すことができます。

```php:名前空間内の関数を呼び出す例
名前空間名\関数名;
```

クラスを使用するときは関数名をクラス名に変えて呼び出します。

```php:名前空間内のクラスを呼び出す
名前空間名\クラス名;
```

##複数の名前空間を同一ファイルで使う時
同一ファイル内で複数の名前空間を定義することは可能です。

```php
<?php
namespace japan;

function greeting() {
    return 'おはよう';
}

namespace usa;

function greeting() {
    return 'hello';
}
```
この構文で複数の名前空間をまとめることは、**どこまでがどの名前空間なのかわかりにくいので進められていません。**
では、どのようにしていくのでしょうか。
###波括弧構文を使う
名前空間を波括弧で囲います。
波括弧内に書かれた関数などはその名前空間に属します。

```php:greet.php
<?php
namespace japan {
    function greeting() {
        return 'おはよう';
    }
};

namespace usa {
    function greeting() {
        return 'hello';
    }
};
```

```php:call.php
<?php
require_once 'japan.php';

echo japan\greeting(); //おはよう
echo usa\greeting(); //hello

```

波括弧を使うことでかなり見やすくなりましたが、コードの可読性を下げてしまうので**同一ファイル内で複数の名前空間を定義することは避けましょう。**（1ファイルごとに1つの名前空間を定義する。）

##複数ファイルで同名の名前空間は使えるのか
複数のファイルで同じ名前の名前空間を使うことはできます。
**しかし同じ名前の関数名などを定義することができません**（どちらも同一名前空間内なので）
なので**サブ名前空間**を用いて名前空間に**ディレクトリのように階層をもたせる**ことで同名の名前空間を定義することができます。
またこのときに、フォルダー構造と名前空間の階層が一致しているとわかりやすいです。（一致していなくてもエラーは起きないがファイルの行方がわからなくなるので一致している方が良い。）

##名前空間の記述
名前空間の指定には

 * 非修飾形式
 * 修飾形式
 * 完全修飾形式
 
の3つがあります。

###非修飾形式
ディレクトリ構造でいう同ディレクトリからの呼び出しで、同じ名前空間にあるため関数名を呼ぶときには名前空間を記述しません。同じ名前空間`japan\tokyo`に属している関数`greeting`を呼び出します。`japan.php`と`greet.php`は同じ名前空間なので関数を呼び出すときには名前空間を記述しません。

```php:japan.php
<?php
namespace japan\tokyo;

function greeting() {
    return 'おはよう';
}
```

```php:greet.php
<?php
namespace japan\tokyo;

require_once 'japan.php';

echo greeting(); //　おはよう
```

###修飾形式
名前空間の階層区切り文字`/`を含んだ名前のことで、現在の名前空間を起点に解釈されます。
ディレクトリ構造でいうドキュメント相対パス。
`japan.php`を名前空間　`japan\tokyo`、`greet.php`を名前空間`japan`にそれぞれ定義して`greet.php`で関数`greeting`を呼び出します。`greet.php`は`japan.php`の名前空間よりも1階層上に属しているので呼び出すには`tokyo\greeting`として呼び出します。

```php:japan.php
<?php
namespace japan\tokyo;

function greeting() {
    return 'おはよう';
}
```

```php:greet.php
<?php
namespace japan;

require_once 'japan.php';

echo tokyo\greeting(); //おはよう
```

###完全修飾形式
ディレクトリ構造でいうルート相対パスにあたり、記述するときは最初に`\`を記述して最上位階層から始めます。

```php:japan.php
<?php
namespace japan\tokyo;

function greeting() {
    return 'おはよう';
}
```

```php:greet.php
<?php
namespace japan;

require_once 'japan.php';

echo \japan\tokyo\greeting(); //おはよう
```
##グローバル名前空間
名前空間を定義しないとディレクトリ構造でいうルートディレクトリにあたる`グローバル名前空間`に属することになります。
名前空間を宣言しない場合と、`namespace`の名前空間名を省略した場合はどちらもグローバル名前空間に属していることになります。

```php:名前空間名を省略した場合
namespace {
    function hoge() {
        // 略
    }
}
```

```php:名前空間を宣言しない場合
function() {
    // 略
}
```

##インポートとエイリアス
長い名前空間をその都度全部書いていくことはすごく手間なので`use`を使って名前空間をインポートしたりエイリアスを作成することができます。`use`を使うことで長い名前空間のクラスや関数名を全部記述しなくても、**本来のクラス名や関数名だけで使用することができる**ようになります。（※インポート　:取り込み、読み込み）

###　クラスをインポート

```php:クラスをインポート
use 完全修飾形式のクラス名;
```

```php:japan.php
<?php
namespace asia\japan\tokyo;

class language {
    function greeting() {
        return 'おはよう';
    }
}
```

```php:greet.php
<?php
require_once 'japan.php';

use asia\japan\tokyo\language;

$a = new language;
echo $a->greeting();
```

### 関数をインポート

```php:関数をインポート
use function 完全修飾形式の関数名;
```

```php:japan.php
<?php
namespace asia\japan\tokyo;

function greeting() {
    return 'おはよう';
}
```

```php:greet.php
<?php
require_once 'japan.php';

use function asia\japan\tokyo\greeting;

echo greeting(); // おはよう
```
###定数をインポート

```php:定数をインポート
use const 完全修飾形式の定数名;
```

```php:japan.php
namespace asia\japan;

<?php
namespace asia\japan;

const CAPITAL = '東京';
```

```php:capital.php
<?php
require_once 'japan.php';

use const asia\japan\CAPITAL;

echo CAPITAL; // 東京
```
###注意点
* use命令は必ずグローバルスコープ、またはnamespaceブロック直下で呼び出す。（classやfunction内では呼び出すとができない。）
* use命令によるインポートは読み込んでいる現在のファイルのみで認識できるので、use命令を記述したファイルを`require_once`で読み込んだ先のファイルでは認識されない。

###エイリアス

エイリアスとは日本語で`偽名、別名`という意味になり名前空間などの別名を作ることができます。

```php
use 名前空間 as 名前
```

```php:japan.php
<?php
namespace asia\japan\tokyo;

class language {
    function greeting() {
    return 'おはよう';
    }
}
```

```php:greet.php
<?php
require_once 'japan.php';

use asia\japan as japan;

$japanese = new japan\tokyo\language;
echo $japanese->greeting(); //　おはよう
```

## 参考リンク
[【PHP超入門】名前空間（namespace・use）について](https://qiita.com/7968/items/1e5c61128fa495358c1f)
[PHPの名前空間とクラス名のエイリアス、オートロード](https://atmarkit.itmedia.co.jp/ait/articles/1808/01/news009.html)

## 参考図書
[独習PHP　第4版](https://www.amazon.co.jp/%E7%8B%AC%E7%BF%92PHP-%E7%AC%AC4%E7%89%88-%E5%B1%B1%E7%94%B0%E7%A5%A5%E5%AF%9B-ebook/dp/B09372PSG7/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=3GK9N9P6L3JYM&keywords=%E7%8B%AC%E7%BF%92php&qid=1639470403&sprefix=dokusyuu%2Caps%2C271&sr=8-1)