PHPのオブジェクトから、自身のアクセス不能メソッドを静的コンテキストで呼び出せない件（追記あり）

# まとめ

- あるオブジェクト内で自身のクラスの定義されていないメソッドを呼び出す場合、静的コンテキストで動く`__callStatic`を呼び出せない。
- どんな呼び出し方をしても、オブジェクトコンテキストで動く`__call`が呼び出される。
- 別のクラスであれば、同じ書き方で意図通り静的コンテキストの`__callStatic`を呼び出せる。
- オブジェクト内で自分が属するクラスの `__callStatic` を呼び出したい場合は、直接 `self::__callStatic()` と書けば良い。

※ 追記あり

@rana_kualu さんが[自分自身から__callStaticを呼び出したい](https://qiita.com/rana_kualu/items/d6e96d073fbb95692afe#_reference-985e5a53b3f4cc3cbf3d)にて、この様な動作になった経緯について纏めて下さいました。ありがとうございます。

# 検証コード
- PHPバージョン7.0.30
- オブジェクトメソッドから、様々な方法で到達不能なメソッドの静的呼び出しを試みる。

```php
class A
{
    public function object_method()
    {
        print("A のオブジェクトメソッドから、自身のクラス(A)のアクセス不能メソッドを呼び出す".PHP_EOL);
        self::check('self::check()');
        static::check('static::check()');
        A::check('A::check()');
        call_user_func([__CLASS__, 'check'], 'call_user_func');
        forward_static_call([__CLASS__, 'check'], 'forward_static_call');

        print(PHP_EOL);

        print("A のオブジェクトメソッドから、別のクラス(B)のアクセス不能メソッドを呼び出す".PHP_EOL);
        $b = get_class(new B());
        B::check('B::check()');
        call_user_func([$b, 'check'], 'call_user_func');
        forward_static_call([$b, 'check'], 'forward_static_call');
    }

    // アクセス不能メソッドをオブジェクトのコンテキストで実行したときに起動
    public function __call($name, $args) {
        print("__call (Object context) {$name} {$args[0]}". PHP_EOL);
    } 

    // アクセス不能メソッドを静的コンテキストで実行したときに起動
    public static function __callStatic($name, $args) {
        print("__callStatic (Static context) {$name} {$args[0]}". PHP_EOL);
    } 
}

class B extends A
{
}

$a = new A();
$a->object_method();
```

# 実行結果

- Aのオブジェクトメソッドからのクラス A のアクセス不能メソッドの呼び出しは、全てオブジェクトコンテキストの `__call`となった。
- 別のクラス B は、同じ書き方で静的コンテキストの `__callStatic`が呼ばれた。

```
A のオブジェクトメソッドから、自身のクラス(A)のアクセス不能メソッドを呼び出す
__call (Object context) check self::check()
__call (Object context) check static::check()
__call (Object context) check A::check()
__call (Object context) check call_user_func
__call (Object context) check forward_static_call

A のオブジェクトメソッドから、別のクラス(B)のアクセス不能メソッドを呼び出す
__callStatic (Static context) check B::check()
__callStatic (Static context) check call_user_func
__callStatic (Static context) check forward_static_call
```


# 追記 : 仕様を読んでの理解

まず、指摘を受けた[スコープ定義演算子 (::)](http://php.net/manual/ja/language.oop5.paamayim-nekudotayim.php) は静的コンテキストで起動するという機能はありませんでした。ご指摘ありがとうございます。
また、 `static::`（静的遅延束縛）、および内部で静的遅延束縛を使う `forward_static_call` について。[遅延静的束縛](http://php.net/manual/ja/language.oop5.late-static-bindings.php)は「静的コンテキストで『参照できる』」だけで、『参照する』とも『参照を優先する』とも書いていません。

アクセス不能メソッドの実行時に呼ばれる `__call` と `__callStatic` の挙動を見ると、
オブジェクト内で**自身のクラス**のアクセス不能メソッドを参照する場合、書き方の如何に関わらず、
`__call` が呼ばれます。**オブジェクト化していない別のクラス**のアクセス不能メソッドであれば `__callStatic` が呼ばれます。

静的メソッドと静的でないメソッドは共存できません。よって、通常は何の問題もありません。ただし、マジックメソッド（`__call` と `__callStatic`）を呼び出すメソッドの場合は、実行場所によってどちらが動くか変わってしまうという事になります。これはシンプルに「**あるオブジェクト内で自分のクラスのメソッドを呼び出すなら、オブジェクトコンテキストになる。書き方は関係ない**」と考えれば良いと思いました。

尚、オブジェクト内で自分が属するクラスの `__callStatic`を呼び出したい場合は、直接 `self::__callStatic()` と書けば良いです。

```php
class A
{
    public function object_method()
    {
        // `__callStatic` したいなら直接呼べばOK
        self::__callStatic('check', ['__callStatic']);
    }

    // アクセス不能メソッドを静的コンテキストで実行したときに起動
    public static function __callStatic($name, $args) {
        print("__callStatic (Static context) {$name} {$args[0]}". PHP_EOL);
    }
}
```

以上。