はじめに
一年たった頃に、ようやくふわっとしていたthis
について理解できた時があったので、その気付いたときの記録とthis
について僕なりの言葉で解説したいと思います。
1年目まで勘違いしていた点
言語に関係なく、this
はブロックを抜けた外のスコープを指していると思っていた。
※今回はPHPのコードを読んでいる際に間違いに気付きました。
結論(正解)
PHP
とJavaScript
(アロー関数の定義と通常のfunction
定義)で違いがあり、ややこしいのでご注意を。
-
PHPの
$this
- クラスインスタンス(自分自身)を指している。
-
JavaScriptの
this
- アロー関数の場合
- アロー関数は関数定義時(定義場所)の1つ前のコンテキスト(PHPみたいな挙動)
- 通常の
fuction
の場合- 関数呼び出し元(関数呼び出し時)がコンテキストになる
- アロー関数の場合
具体例(PHPの$this挙動の説明)
- 当時PHPでエラー原因を探るためデバッグをしていてその過程で
PHP
での$this
の本当の意味について気付いたので、見ていく
以下説明は、PHP
とJavaScript
のthis
の挙動の違いではなく、あくまでPHP
のthis
の本当の挙動に気付いたときの記録です。
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
の挙動は、PHP
とJavaScript
とそしてさらにアロー関数
と通常関数
などによって変わってくるのでかなり複雑で気付くまでに時間がかかってしまいました。
ちょっと気付くまでの仮定が分かりづらかったかもですが、、、
何か間違いがあればご指摘いただけると幸いです。