エンジニア1年たった頃にようやくPHPとJavaScriptの「this」の挙動の違いを理解できた話

### はじめに

一年たった頃に、ようやくふわっとしていた`this`について理解できた時があったので、その気付いたときの記録と`this`について僕なりの言葉で解説したいと思います。

### 1年目まで勘違いしていた点

言語に関係なく、`this`はブロックを抜けた外のスコープを指していると思っていた。

※今回はPHPのコードを読んでいる際に間違いに気付きました。

### 結論(正解)
:::note warn
`PHP`と`JavaScript`(アロー関数の定義と通常の`function`定義)で違いがあり、ややこしいのでご注意を。
:::


- **PHPの`$this`**
    - クラスインスタンス(自分自身)を指している。
- **JavaScriptの`this`**
    - アロー関数の場合
        - アロー関数は関数定義時(定義場所)の1つ前のコンテキスト(PHPみたいな挙動)
    - 通常の`fuction`の場合
        - 関数呼び出し元(関数呼び出し時)がコンテキストになる

### 具体例(PHPの$this挙動の説明)

- 当時PHPでエラー原因を探るためデバッグをしていてその過程で`PHP`での`$this`の本当の意味について気付いたので、見ていく

:::note warn
以下説明は、`PHP`と`JavaScript`の`this`の挙動の違いではなく、あくまで`PHP`の`this`の本当の挙動に気付いたときの記録です。
:::

app/aaa/bbb/ccc.php

- `getAAA()部分を辿る`

```php
public function getAAAInfo(string $aaa_id, ?string $bbb_id, string $aaa_token): array
    {   
				//...(略)
        try {
            $this->aaa_info = Hoge::before($aaa_id, $bbb_id, $aaa_token)
                                           ->getHoge() // ここを見てく
                                           ->toArray();
```

app/bbb/ccc/ddd/Hoge.php

- こちらにジャンプするので、今度は`getHoge()`をたどってみていく

```php
use Abcd\Efcd as HogeAccount;

class HogeAccount extends HogeBase
{
    public function __construct(string $aaa_id, ?string $bbb_id, $ccc, string $aaa_token = null)
    {
        parent::__construct($aaa_id, $bbb_id, $cccc, $aaa_token);
        
        $this->service = new HogeAccount($this->aaa_id);
        
    }

	/**
     * Hoge情報取得
     */
    public function getHoge(): self
    {
        // ここのdo()を見てく
        $this->res = $this->do('getHoge', self::$hoge_field)->hogeData();
        return $this;
    }
```

app/Aaa/Bbb/Ccc/HogeBase.php

- `$this→service→$method`実行でエラーが出ている
    - `$method`は、`getHoge`という文字列が入っていて、`service`をジャンプして見てみるが見当たらない(このとき$thisの意味を理解していないため、違うファイルを見に行ってしまっていた)

```php
protected function do(string $method, array $fields = [], array $params = [], bool $pending = false)
    {
			//...(略)
            try {
                // ここでエラーが出ていた
                $result = $this->service->$method($fields, $params, $pending);

		     //...(略)
```

上記で`service`の中にある、`$method(getHoge)`を見つけるには

`$this→service`がどこの何者なのかを知る必要がある。

ここで`$this`はメソッドのブロックの外のスコープの意味ではなく、クラスインスタンス(自分自身)を指しているため、`do()`を実行している箇所(`app/bbb/ccc/ddd/Hoge.php`)のクラスインスタンスは、`HogeBase`を継承している`HogeAccount`なので、に戻って、そのファイル内でserviceがいるはずなので、探し出す。

app/bbb/ccc/ddd/HogeAccount.php

- `construct()`内で`new HogeAccount`(`as`で名前変えられているが、`use`のパスからファイルを辿れる。)されていた

```php
// ここを辿る
use Abcd\Efcd as HogeAccount;

class HogeAccount extends HogeBase
{
    public function __construct(string $aaa_id, ?string $bbb_id, $ccc, string $aaa_token = null)
    {
        parent::__construct($aaa_id, $bbb_id, $ccc, $aaa_token);
        
		//　serviceはここにいた(正体はHogeAccount)
        $this->service = new HogeAccount($this->aaa_id); 
        
    }
```

vendor/aaaaa/bbbbb/HogeAccount.php

**無事にHogeAccountに該当のメソッドが見つかって、ここで`$this`の本来の意味に気付く・・・。**

```php
class HogeAccount extends HogeObject {

//...(略)

public function getHoge(array $fields = array(), array $params = array(), $pending = false) {
    $this->hugaId();
		
		//...(略)
```

### おわりに

`this`の挙動は、`PHP`と`JavaScript`とそしてさらに`アロー関数`と`通常関数`などによって変わってくるのでかなり複雑で気付くまでに時間がかかってしまいました。

ちょっと気付くまでの仮定が分かりづらかったかもですが、、、
何か間違いがあればご指摘いただけると幸いです。