LoginSignup
11
10

More than 1 year has passed since last update.

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

Posted at

はじめに

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

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

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

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

結論(正解)

PHPJavaScript(アロー関数の定義と通常のfunction定義)で違いがあり、ややこしいのでご注意を。

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

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

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

以下説明は、PHPJavaScriptthisの挙動の違いではなく、あくまでPHPthisの本当の挙動に気付いたときの記録です。

app/aaa/bbb/ccc.php

  • getAAA()部分を辿る
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()をたどってみていく
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の意味を理解していないため、違うファイルを見に行ってしまっていた)
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のパスからファイルを辿れる。)されていた
// ここを辿る
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の本来の意味に気付く・・・。

class HogeAccount extends HogeObject {

//...(略)

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

おわりに

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

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

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10