質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.45%

  • PHP

    24613questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

parent:: で親クラスのインスタンスメソッドと静的メソッドの両方にアクセスできるのが腑に落ちません

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 1,302

7968

score 221

サブクラスから parent:: で親クラスのインスタンスメソッド、静的メソッドの両方にアクセスできます。

<?php

class A
{
    protected $firstName;
    protected $lastName;

    public function getName($args1, $args2) {
        $this->firstName = $args1;
        $this->lastName = $args2;
        echo $this->firstName . $this->lastName;
    }

    protected static $staticFirstName;
    protected static $staticLastName;

    public static function getStaticName($args1, $args2) {
        self::$staticFirstName = $args1;
        self::$staticLastName = $args2;
        echo self::$staticFirstName . self::$staticLastName;
    }
}

class B extends A
{
    public function hoge($args1, $args2)
    {
        parent::getName($args1, $args2);
    }

    public function fuga($args1, $args2)
    {
        parent::getStaticName($args1, $args2);
    }
}

$b = new B();
$b->hoge('武蔵','宮本'); // 武蔵宮本
$b->fuga('小次郎','佐々木'); // 小次郎佐々木

これが腑に落ちません。

インスタンス、静的という考え方に誤りがあるのでしょうか。

static のあるプロパティとメソッドはクラスに属することになり、スコープ定義演算子 :: でアクセスします。(インスタンス化なしでアクセスできる)

static のないプロパティとメソッドはインスタンスに属することになり、アロー演算子 -> でアクセスします。

上記のように私の中では理解しております。

親クラスのインスタンスメソッドにアクセスするなら parent-> 、静的メソッドにアクセスするなら parent:: という記述なら腹落ちしますが、parent:: でインスタンスメソッドと静的メソッドの両方にアクセスできることが腑に落ちません。

なぜ、parent:: で親クラスのインスタンスメソッドと静的メソッドの両方にアクセスできるのでしょうか?

私が根本的に誤って理解しているのかと思います。

どこに誤りがあるのか教えてください((_ _ (´ω` )

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+4

サブクラスから parent:: で親クラスのインスタンスメソッド、静的メソッドの両方にアクセスできます。

違うなぁ。混乱しやすいのかもしれないけど。
インスタンス(動的プロパティ、動的メソッド)にアクセスするのはアロー演算子、
クラス(静的プロパティ、静的メソッド)にアクセスするのがダブルコロン。

お約束のリファレンスより。

PHP: スコープ定義演算子 (::) - Manual
self:: で自クラスのプロパティ、静的メソッドにアクセスできる。
parent:: で親クラスのプロパティ、静的メソッドにアクセスできる。

PHP: アクセス権 - Manual

public 宣言されたクラスのメンバーには、どこからでもアクセス可能です。
protected 宣言されたメンバーには、 そのクラス自身、そのクラスを継承したクラス、および親クラスからのみアクセスできます。
private 宣言されたメンバーには、そのメンバーを定義したクラスからのみアクセスできます。 

PHP: static キーワード - Manual

クラスプロパティもしくはメソッドを static として宣言することで、 クラスのインスタンス化の必要なしにアクセスすることができます。 static なプロパティは、インスタンス化されたクラスオブジェクトから アクセスすることはできません (static なメソッドにはアクセスできます)。

PHP: オブジェクトの継承 - Manual

クラスを拡張するとき、サブクラスは親クラスから public と、protected のメソッドをすべてを引き継ぎます。

すっごく時間をかけて説明文を書いてみたけど、
説明が危うく拙い気がしたので、消して、
もうちょっとわかりやすい記事を探してみた。

PHPを愛する試み 〜self:: parent:: static:: および遅延静的束縛〜 - maeharinの日記
PHPの「$this」と「self::」の違い - Qiita


検証コードを書きながら、
親クラスからの継承の話と、
おなじ命名空間での他クラスからのアクセスの話も知っといたほうがいいと思えてきました。

謎なコードを示します。

<?php

class foo {
    public function hoge() { echo 'hoge'; }
    public static function fuga() { echo 'fuga'; }
}

class bar {
    public function piyo() {
        echo foo::hoge();
    }
}
$x = new bar();
$x->piyo();

これ、実行すると、
「Deprecated: Non-static method foo::hoge() should not be called statically」
ってエラーメッセージが出ますが、
「hoge」って出力されます。

class bar {
    public function piyo() {
        echo foo::fuga();
    }
}


とすることでエラーメッセージなしに「fuga」って出力されます。
クラスfooとbarの間には継承の関係はありません
同じ命名空間にいるだけです。

<?php

class foo {
    public const X = 1;
    public static $y = 2;  // staticがないとFatal error
}

class bar {
    public function piyo() {
        echo foo::X . PHP_EOL;
        echo foo::$y . PHP_EOL;
    }
}
$x = new bar();
$x->piyo();


結果は「1(改行)2(改行)」です。
クラスうんぬんいうまえに、スコープ演算子と命名空間のことも知っとかないと、
危ういと思います。
(これが理解できると、フレームワークのソースコードも読めるようになるのかも。)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/11 20:18

    回答と参考サイトありがとうございます。
    また、説明文も考えてくださり、ありがとうございます。

    私の質問の仕方にも問題があったかもしれません((_ _ (´ω` )

    まず、self:: という記述は self キーワードにスコープ定義演算子を付けてるという理解です。
    parent :: も同じく parent キーワードにスコープ定義演算子を付けてるという理解です。
    self は記述してる自クラスを、parent は親クラスを返すという理解です。

    スコープ定義演算子は下記の3つにアクセスできるとPHPマニュアルに記載があります。

    1. static
    2. 定数
    3. オーバーライドされたクラスのプロパティやメソッド

    今回のコードの場合だと、B クラスの fuga メソッドの場合は親クラスにある static ありの getStaticName メソッドをコールしているため「 1. static」に該当しているかと思います。
    これは納得できます。

    ```
    public function fuga($args1, $args2)
    {
    parent::getStaticName($args1, $args2);
    }
    ```

    もう一つの B クラスにある hoge メソッドは 1〜 3 のどれにも該当しないと思うのですが、なぜ parent:: というスコープ定義演算子を使ってアクセスできるのでしょうか?

    お手すき時にアドバイスいただると助かります((_ _ (´ω` )

    キャンセル

  • 2018/12/12 04:09

    回答したはずの者が言うのは変なのですが
    > クラス(静的プロパティ、静的メソッド)にアクセスするのがダブルコロン。
    とのことですが、「実際の挙動としてparent::でparentの動的メソッドにアクセス可能である」が質問の趣旨だと思います。また、検証してみた結果、m6u様の回答やマニュアルにそわない動作をしているように思えてきました。

    キャンセル

  • 2018/12/12 09:38

    クラスの持ち物が静的プロパティ、静的メソッドで、
    インスタンスの持ち物が動的プロパティ、動的メソッドという解釈。
    スコープ演算子がアクセスできるのがクラスの持ち物である静的プロパティ、静的メソッド。
    だから、
    「オーバーライドされたクラスのプロパティやメソッド」
    というよりも
    「オーバーライドされたクラスの、public宣言protected宣言された、静的プロパティや静的メソッド」
    が正しいところ。

    キャンセル

  • 2018/12/12 09:46

    phpのマニュアルの記載は、特に日本語訳は、きれいに正しく解釈できるとは言えず、
    部分を取り上げると誤解を生じる場合のありますので、
    よその解説記事やサンプルコードを動かすなどして
    staticをつけたり外したり、publicをprotectedやprivateに書き換えてみるなどして、
    いじめてみるとよく分かると思います。

    キャンセル

  • 2018/12/12 09:59 編集

    お二方、何度も返信していただきありがとうございます((_ _ (´ω` )

    > クラスの持ち物が静的プロパティ、静的メソッドで、
    > インスタンスの持ち物が動的プロパティ、動的メソッドという解釈。

    私の中では static があるプロパティとメソッドが静的プロパティと静的メソッドという解釈です。
    static がないプロパティとメソッドが動的プロパティ、動的メソッドという解釈です。
    上記のような理解ですので static のない親クラスに partent:: でアクセスできるのが腑に落ちませんでした。

    m6u さんは static のあり・なし関係なしに下記のように記述した定義は全て静的プロパティ、静的メソッドという解釈なのでしょうか?

    class A {
    public $a = 1;
    public static $b = 2;
    public function hoge() {}
    public static function fuga() {}
    }

    動的プロパティや動的メソッドは、あくまでも new クラス名 でインスタンス化して使うプロパティやメソッドが動的プロパティ、動的メソッドという解釈なのでしょうか?

    お手すき時にアドバイスいただると助かります((_ _ (´ω` )

    キャンセル

  • 2018/12/12 10:52

    スコープ演算子をクラスと継承の話だけですることに違和感を覚えたので、
    回答内に説明を加えました。

    キャンセル

  • 2018/12/12 16:53

    静的メソッドじゃないのに $classname:: で呼び出しできちゃうっていう問題はPHPがいい加減なだけ
    ちなみに静的メソッドを $instance-> で呼び出すこともできるてしかもこっちは注意文も出ない
    PHP7.0でも直さんかったってことはもう直らんのじゃないかな

    https://stackoverflow.com/questions/3754786/calling-non-static-method-with-double-colon

    キャンセル

  • 2018/12/12 17:03

    まぁ、美しい言語じゃなくて、実利をとってる感じはする。

    キャンセル

  • 2018/12/13 11:34 編集

    > m6u さん
    追記と参考サイトありがとうございまいました。
    PHP7 では $this::foo()->foo()::foo() のようなアクセスもエラーなしでできるようで(やらないのが無難だと思いますが... 実行結果:https://3v4l.org/1dTbq)、-> と :: についてちゃんと理解できていないので、実際に試して実行結果から学びたいと思います。
    何度も返信いただきありがとうざいました。

    > KazuhiroHatano さん
    参考サイトありがとうございました。

    キャンセル

checkベストアンサー

+3

staticと、static::は別物です。

static::もparent::もクラスを返します。
$this->の代わりにself::としても動作します。


改めて。
スコープ定義演算子 (::) のマニュアルの

「ダブルコロン」は、トークンのひとつです。 static, 定数 およびオーバーライドされたクラスのプロパティやメソッドにアクセスすることができます。

の「オーバーライドされたクラスのプロパティやメソッド」の部分は正確でないのではないかと考えるに至りました。
マニュアル自身、クラスの基礎の「例2 $this 疑似変数の例」において、A::foo();という書き方で、クラスAのstaticでもオーバーライドされてもいないメソッドfooにアクセスする例を書いてます。
プロパティについて言えば逆にオーバーライドしていてもstaticでないとparent::によって参照することができませんでした。

<?php
class A {
    public function a() { return 1; }
    public $a1 = "prop";
}
class B extends A {
    public function b() { return parent::a(); }
    public function b1() { return parent::$a1; } //PHP Fatal error:  Uncaught Error: Access to undeclared static property: A::$a1
    public $a1 = "new";
}

現在の私の理解としては

「ダブルコロン」は、トークンのひとつです。 「定数」または「staticなクラスのプロパティ」、「クラスのメソッド」にアクセスすることができます。

ではないかと思います。
また、質問者様ご提示のような書き方をしたときに(parent->でなく)parent::で動作する理由のもう一つとして、$this疑似変数が、(呼ばれ方にかかわらず)呼び出し元のオブジェクト指すことも影響しています。parent::getName()として、AのgetNameが呼ばれたときその関数本体の中で使われる$thisは、->を使っていないにもかかわらず、getNameを呼んだ(Aのサブクラスの)インスタンスを適切に指してくれます。詳しくは、上に引用した"クラスの基礎"の説明および例をご参照ください。

こう書いてしまうとやや余談になりますが、先に書いたself::についてはこれもstaticでない自クラスのメソッドを($this->でなくself::で)呼べるという意図でした。下記のパターンもご参考としていただければと思います。

class A {
    public function a() { return 1; }
}
class B extends A {
    public function b() { return parent::a(); }
}
class C extends A {
    public function c() { return A::a(); }
}
class D extends A {
    public function d() { return $this->a(); }
}
class E extends A {
    public function e() { return self::a(); }
}
// class F {
//     public function f() { return A::a(); } //fatal error
// }
$b = new B();
$c = new C();
$d = new D();
$e = new E();
//$f = new F();
// A::a(); // fatal error
var_dump($b->b());
var_dump($b->b1());
var_dump($c->c());
var_dump($d->d());
var_dump($e->e());
//var_dump($f->f());

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/11 20:35

    回答ありがとうございます。

    > staticと、static::は別物です。

    プロパティやメソッドの前に static を付けると静的プロパティ、静的メソッドになるという理解です。
    static:: は staic キーワードにスコープ定義演算子を付けているという理解です。

    > static::もparent::もクラスを返します。

    例えば、parent なら親クラスを指定しているという理解です。

    $this->の代わりにself::としても動作します。

    self:: は statc ありのプロパティにアクセスするものなので、プロパティの前に statc を付ければ $this-> を self:: に変えても動作するということですよね?

    キャンセル

  • 2018/12/12 04:04

    結論から申しまして質問者さまが言っておられるとおりparent::でインスタンスメソッドが呼べるのはマニュアルのうえではおかしい、と思うに至りました。回答を追記しました。

    > static:: は static キーワードにスコープ定義演算子を付けているという理解です。
    「static キーワードにスコープ定義演算子を付けている」というのは変ではないかと思います。引用なさっておられるとおり、マニュアルに従えば本来的に`::`はstaticなプロパティやメソッドへのアクセスしか許さないはずなので、それにさらにstaticをかけるというのは変です。static::におけるstaticはプロパティやメソッドにつける「静的」ということとは違う働きと考えたほうがよいと思います(m6u様の引用のphpを愛する試みが非常に参考になります)

    > self:: は statc ありのプロパティにアクセスするものなので、プロパティの前に statc を付ければ $this-> を self:: に変えても動作するということですよね?
    こちらは回答にも追記しましたが、parent::と同じく、self::によって、staticでない自クラスのメソッドにアクセス可能です。

    キャンセル

  • 2018/12/12 10:42 編集

    ご返信ありがとうございます。

    > マニュアル自身、クラスの基礎の「例2 $this 疑似変数の例」において、A::foo();という書き方で、クラスAのstaticでもオーバーライドされてもいないメソッドfooにアクセスする例を書いてます。

    そうなんですよね、 deprecated や strict の通知が表示されますが、クラスの外から :: で static のないメソッドにアクセスできるんですよね。

    これは意図していない動作で今後はエラーになる可能性もあると下記の記事で強そうな方がそのようなことを言及されていたと思います。(今はqrunch がエラーで見れない;;)
    https://qrunch.io/entries/nXidDatSJfnn9OnS/NiCLd1tcAqFPKHNs

    > プロパティについて言えば逆にオーバーライドしていてもstaticでないとparent::によって参照することができませんでした。

    static なしの親プロパティにアクセスできるか試してはいなかったのですが、仰るとおり、Fatal error になりました。
    サンプルコードありがとうございます。

    > 先に書いたself::についてはこれもstaticでない自クラスのメソッドを($this->でなくself::で)呼べるという意図でした。下記のパターンもご参考としていただければと思います。

    なんと、self:: も static ではない自クラスのメソッドを呼べるのですね。うーむ。

    PHP のマニュアルのスコープ定義演算子の説明が正しくない、もしくは、

    ・static,
    ・定数
    ・オーバーライドされたクラスのプロパティやメソッド

    はクラスの外からアクセスするときの話で、クラスコンテキスト内で使う :: は別という解釈をすれば辻褄があうのかなぁと思いました。

    キャンセル

  • 2018/12/12 11:15

    > クラスの外からアクセスするときの話
    これがm6u様が追記なさった名前空間の話だと思いますが、それでもマニュアルの、static, 定数 およびオーバーライドされたクラスのプロパティやメソッド、という書き方は不適切だと思います。英独仏版を比較参照しても、7968様が仰るとおり
    ・static
    ・定数
    ・オーバーライドされたクラスのプロパティやメソッド
    の3つに読み取るのが妥当です。しかし、クラス外からClass::method()とするときは、オーバーライドされたクラスの静的(static)メソッドに限られるため、最低でもマニュアルの表現はstaticが3つ目を修飾する形容詞となるようにかえなければ不正確だと思います。

    キャンセル

  • 2018/12/12 16:56 編集

    何度もご返信いただき、ありがとうございます。

    私の考えと papinianus さんの考えは、ほぼ同じなのかなと思っています。
    PHP マニュアルを English にして確認しても「オーバーライドされたクラスのプロパティやメソッド」というのは誤訳ではないと思っています。

    ちなみにですが「オーバーライド」という言葉の意味について確認させてください。

    「オーバーライドされたクラスのプロパティやメソッド」というのは普通は下記のように static なしのプロパティやメソッドをサブクラスで再定義することをオーバーライドと呼びますよね?

    ```
    <?php

    class A
    {
    public $hoge = 'Aプロパティ';
    public function fuga()
    {
    return 'Aメソッド';
    }
    }

    class B extends A
    {
    public $hoge = 'Bプロパティ';
    public function fuga()
    {
    return 'Bメソッド';
    }
    }

    // echo B::$hoge; これはFatal error
    echo B::fuga(); // Strict Standards の警告が表示されるけど、結果も表示される
    ```

    下記のように static ありのプロパティやメソッドをサブクラスで再定義することはオーバーライドとは呼びませんよね?

    ```
    <?php

    class A
    {
    public static $hoge = 'Aプロパティ';
    public static function fuga()
    {
    return 'Aメソッド';
    }
    }

    class B extends A
    {
    public static $hoge = 'Bプロパティ';
    public static function fuga()
    {
    return 'Bメソッド';
    }
    }

    echo B::$hoge; // Bプロパティ
    echo B::fuga(); // Bメソッド
    ```

    これを仮にオーバーライドと呼んだとしても、`A::$hoge` や `A::fuga()` でアクセスできるので、オーバーライド関係なしにアクセスできるので「オーバーライドされた」と記述する意味はないのかと思っています。

    「オーバーライドされたクラスのプロパティやメソッド」というのは何を言いたかったのでしょうかね?(あれ?作者の気持ちを答えよという国語の問題?w)

    結果から推察するにしても static なしのプロパティは fatal error で、メソッドはアクセスできても警告が表示されますからね。
    「オーバーライドされたクラスのプロパティやメソッド」のように「プロパティとメソッド」とは記載しないですよね...
    static を付ければオーバーライド関係なしにアクセスできるので、「オーバーライドされた」とは記載しないですよね...
    うーん...

    キャンセル

  • 2018/12/12 17:09

    長々と書いてしまいましたが、PHPマニュアルの説明は誤りで、papinianus さんが記載された下記の内容が正しいということですね。

    「ダブルコロン」は、トークンのひとつです。 「定数」または「staticなクラスのプロパティ」、「クラスのメソッド」にアクセスすることができます。

    キャンセル

  • 2018/12/12 17:13

    私も分かったつもりでしたが今や7869様と同じ疑問を持っています。

    静的でもオーバーライドと呼ぶと思います(もちろん、偶然同じじゃなくて、継承関係がある場合)

    ・「オーバーライドされた」というのの読解
    オーバーライドされた(親クラス)側は、インスタンスが子クラスであれば、どのようにメソッドをコールしても(PHPでは難しいですが親のクラス型の変数に代入してメソッドを呼んでも)、オブジェクト指向の多態性によって、親(オーバーライドされた)側のメソッドは呼ばれない、となるのがオブジェクト指向的な理解だと思います。
    それを`::`の前にクラスを指定したら、呼び出し元のオブジェクトコンテクスト(インスタンス)によって$thisが何になるかにかかわらず、指定されたクラスのメソッドが使える、ということに意味がる文章だと理解しています。この説明もなんか回りくどいですが。
    くだけて言えば、「->だと隠されちゃうメソッドに::だったらアクセスできるよ」という意図かと思ってます(、今のところは)。

    キャンセル

  • 2018/12/12 17:13

    正しいというか、そういう風な動作にしか見えないです。

    キャンセル

  • 2018/12/13 11:34 編集

    なるほど、静的でも継承して同名で定義すればオーバーライドになるのですね。
    PHP7 では $this::foo()->foo()::foo() のようなアクセスもエラーなしでできるようで(やらないのが無難だと思いますが... 実行結果:https://3v4l.org/1dTbq)、-> と :: についてちゃんと理解できていないので、実際に試して実行結果から学びたいと思います。
    何度も返信いただきありがとうざいました。

    キャンセル

  • 2018/12/13 13:24

    こちらこそ勉強になりました。ありがとうございます

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.45%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • PHP

    24613questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • トップ
  • PHPに関する質問
  • parent:: で親クラスのインスタンスメソッドと静的メソッドの両方にアクセスできるのが腑に落ちません