maisumakun さんの回答がほぼ全てだと思うのですが、「まだ回答を求めています」ということなので、もう少しかみ砕いて説明してみます。
php.netの解説に上記のようにあるのですが、「そのオブジェクトのクラス」が何を指すのかわかりません。
上記の例でstaticはクラスAを指す、ということでしょうか?
php
1$c = new C();
2$c->test(); //fails
この場合、「そのオブジェクト」は $c
です。
また、$c
は new C()
を代入されているので「そのオブジェクトのクラス」は C
ということになります。
その上で……。
test
メソッドは A
クラスにしか存在していません。
そのため、 $c->test();
を実行した場合、呼び出されるのは A
クラスのメソッドです。
testメソッド内の挙動については下記のとおりになります。
php
1 public function test() {
2 /* testメソッド自体はAクラスのもの。
3 * Aクラスの「$this」、つまりAクラスのfooメソッドを呼び出す。
4 * ⇒問題なし(Aクラスのメソッドが、Aクラスのprivateメソッドを呼んでいるので)
5 */
6 $this->foo();
7
8 /* 前述のとおり、Cクラスのfooメソッドを呼ぼうとする。
9 * testメソッド自体はAクラスのもの。
10 * ⇒AクラスのtestメソッドからCクラスのprivateメソッドは呼べない
11 * ⇒エラーになる。
12 */
13 static::foo();
14 }
警告
PHP 7 では、static でないメソッドを静的にコールすることが非推奨になりました。 E_DEPRECATED レベルの警告が発生します。 将来的にはサポートされなくなる見込みです。
とあります。
static::foo();
はこの警告に当てはまるコード、という理解で良いですよね?
いいえ。
PHPのマニュアル( http://php.net/manual/ja/language.oop5.static.php )を再読していただきたいのですが、上記制限が入るのは「static メソッド」です(同じ「static」というキーワードのため紛らわしいのですが、 static::
とは別物です。詳細は後述します)。
そして、staticメソッドというのは
class Hoge
{
public static function fuga()
{
}
}
といった「メソッド宣言に"static"と書かれているもの」を指します。
非推奨になった呼び出し方、というのは
php
1class Hoge
2{
3 public static function fuga() // staticメソッド
4 {
5 }
6
7 public function piyo() // staticではないメソッド
8 {
9 }
10}
というクラスがある時に、クラスオブジェクトを作らずに直接「staticではないメソッド」を呼ぶことです。
php
1$hoge = new Hoge();
2$hoge->piyo(); // OK
3
4Hoge::piyo(); // 非推奨
今回の fooメソッド は、Aクラス・Cクラスともに private function foo()
で宣言されている(=メソッド宣言にstaticと書かれていない)ので、これはstaticメソッドではありません。
static::foo()
については、上記マニュアルの一番上に書かれている
ヒント
このページでは、static キーワードを使って静的なメソッドやプロパティを定義する方法を説明します。 static は、 静的な変数の定義 や 静的遅延束縛 にも使えます。これらの場合の static の使い方は、 それぞれのページを参照ください。
の「静的遅延束縛」に該当しています。
↓静的遅延束縛のマニュアル
http://php.net/manual/ja/language.oop5.late-static-bindings.php
以下、回答へのコメントを受けて追記します。
一つめの部分について、ご理解いただけたようで何よりでした。
以下、二つめの部分についての疑問に対する回答……に入る前に
この「静的にコールする」の定義はマニュアルなどで説明されていますでしょうか?もしソースがあれば教えて頂けますでしょうか。
を解消しておきましょう。
まず、
・static メソッド=静的メソッド(staticの日本語訳が"静的"なので)
・非static メソッド=静的ではないメソッド≒動的メソッド
です。
そして、この「静的メソッド」と「動的メソッド」というのは、PHP独自の概念ではなく、オブジェクト指向型言語全般(Java、C、等々)に一般的に存在する概念である、ということはご理解ください。
解説ページ(PHPのページではありませんが、わかりやすくまとまっていたのでご紹介です)
https://yryr.me/programming/csharp/beginner/object-model/object-model-static-dynamic-difference.html
そして、ここで「(メソッドを)静的にコールする(calling methods statically)」と書かれているのは、超意訳すると「静的(メソッドを、静的メソッドを呼び出すために用意された方法で)コールする」ということになるかと思います。
以上の内容を踏まえ、具体的なご質問への回答です。
「静的にコールする」=「クラスオブジェクト(インスタンス)を作らずに直接メソッドを呼ぶ」ということでしょうか?
はい、本質的なところはそのとおりです(上記解説ページ参照のこと)。
そして、通常は
「::(スコープ定義演算子)を用いてメソッドを呼び出すこと」を「静的にコールする」と認識していました。
という認識でも問題ないはずでした(スコープ演算子を用いてメソッドを呼び出す≒クラスオブジェクト(インスタンス)を作らずに直接メソッドを呼ぶために定義された書式がほとんどなので)。
が、「スコープ定義演算子を用いてメソッドを呼び出す([クラス名]::、self::、parent::、static::)」もののうち、「static::」のみ特殊な挙動をします(詳細は後述)。
それで考えると、質問のコードではCのインスタンスを作ってtest()を呼び出している→そのtest()で
static::foo()を呼び出している。
遅延静的束縛によりstaticはCクラスを指す、Cのインスタンスを作っているから、このstatic::foo()は
静的なコールではない、ということでしょうか?
結論が「静的なコールではない」というのは正しいのですが、その理由は、「Cのインスタンスを作っているから」ではありません。
遅延静的束縛のマニュアルに、下記の記載があります。
静的メソッドの場合、これは明示的に指定されたクラス (通常は :: 演算子の左側に書かれたもの) となります。
静的メソッド以外の場合は、そのオブジェクトのクラスとなります。
これを把握した上で、改めて、fooメソッドの宣言部分を見てみましょう。
メソッドの宣言に"static"が付いていません。
つまり、これは「静的メソッド以外」ということになります。
今回は、「静的メソッド以外から、static::を使ってfoo()メソッドが呼ばれた」ので「そのオブジェクトのクラス」のメソッドが動的に呼ばれたのです。
スコープ演算子を使ってメソッドを呼び出した時の動的・静的の違い
・"static::"
・呼出し先メソッドが静的でも動的でも使用できる
・呼出し先メソッドの定義(静的メソッドか動的メソッドか)によって、静的なコールか動的なコールかが変わる
・"[クラス名]::"、"self::"、"parent::"
・呼出し先メソッドが静的な場合しか使用できない
・必ず静的なコールになる(静的メソッドは静的なコールしかできないので)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/01/14 03:11
2019/01/14 05:02
2019/01/14 07:37
2019/01/14 07:38