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

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

ただいまの
回答率

90.52%

  • PHP

    20318questions

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

  • オブジェクト指向

    284questions

    オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

$thisが指すクラスがどれかわかりません。

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 208

awa

score 11

下記のコードを実行すると、ブラウザには"さん、こんにちは。"という表示になりましたが、なぜその表示になるのかわからないので教えていただけないでしょうか。
想定していたのは、"ゲストさん、こんにちは。"でした。

class User{
    private $name = null;

    public function print_hello(){
        print $this->name;
        print "さん、こんにちは。";
    }
}

class Guest extends User{
    private $name = "ゲスト";
}

$guest = new Guest();
$guest->print_hello();

下記のように認識しています。
$guestにはGuestクラスのインスタンスが入っており、GuestクラスはUserクラスを継承している。
Guestクラスは継承しているため、Userクラスのprint_hello()を持っている。
Guestクラスにあるprint_hello()を呼び出すことで、$this->nameでGuestの$nameにアクセスする。

このような結果になったので、$this->nameがUserクラスの$nameにアクセスしているんだろうなと思ってはいるのですが、なぜGuestのインスタンスから読んだのに、$thisがUserクラスを指すのかがわかりません。

どうぞよろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+3

Guestの$nameはprivateだからUserのメソッドからは参照できない

プロパティとしては両方保持しているが
どちらのクラスのメソッドで呼ばれたかでどっちが取得されるかが変わる

こうするとわかりやすい

class hoge{
    private $name='a';
}
class hoge2 extends hoge{
    private $name='b';
}

$hoge2=new hoge2();
var_dump(new hoge2());
/*
object(hoge2)#1 (2) { ["name":"hoge2":private]=> string(1) "b" ["name":"hoge":private]=> string(1) "a" }
*/

両方のプロパティがちゃんといる

protectedなら上書きされて一つだけになる

class hoge{
    protected $name='a';
}
class hoge2 extends hoge{
    protected $name='b';
}

$hoge2=new hoge2();
var_dump(new hoge2());
/*
object(hoge2)#2 (1) { ["name":protected]=> string(1) "b" }
*/

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/30 22:26

    ご回答ありがとうございます。
    おかげで私が下記2点誤解していたことがわかり、今回の結果原因について理解できました。

    (1) 継承したら同じ名前のプロパティとメソッドは全てオーバーライドされる。
      (→継承元がpublicとprotectedならアクセスが可能なためオーバーライドになるが、privateはオーバーライドされずにそのまま同名でも両方とも継承先で保持される。)
    (2) 継承先でメソッドを明記していなくても、継承すればスーパークラスのメソッドが継承先のクラス内に自身のメソッドとしてコピーされている。
    (→継承先でそのメソッドを定義していなければ、スーパークラスのメソッドを呼んでいる。今回の場合は、print_hello()はGuestクラスのメソッドではなくUserクラスのメソッドを呼んでいる。nameがUserとGuestクラスの両方あるが、メソッドはUserクラスのものなので、Userクラスのnameが採用される。一方でもし、nameがオーバーライドされて1つしかなかった場合、メソッドはUserクラスのものが呼ばれるが、オーバーライドした方のnameが採用される。)

    (2)で書いた「一方でもし~」の部分が例外のような感じで$thisが指すオブジェクトが異なってくるのがややこしいなと感じました。

    もし理解が違っていればお手数ですがご指導お願いいたします。

    キャンセル

  • 2018/06/30 23:52

    概ねその理解であっていると思いますが、protectedやpublicではコードで示した通りプロパティは一つになっていてかつどのクラスで定義されたかの情報も保持していません。
    スーパークラスで定義されたメソッドがサブクラスから呼び出された際に、呼び出し元のサブクラスを参照するには「静的遅延束縛」を使います、まあ小難しい名前ついてますが要するにstaticでメソッドを実行したクラスを参照できるよって話です。

    蛇足ですが、serializeした場合なんかはprivateなのかpublicなのかといったアクセス権の情報も保持しないのですが、どのクラスで定義されたプロパティなのかは保持しています、unserializeの時にアクセス権の情報が元と違っていてもエラーになりません、なのでクラス定義を変えてunserializeすることでprivateなプロパティをpublicにしてしまったりもできたりします。

    キャンセル

  • 2018/07/01 00:00

    ×静的遅延束縛 ○遅延静的束縛

    キャンセル

  • 2018/07/01 16:12

    遅延静的束縛、serializeについて全く知らなかったので、そちらも調べてみました。特に遅延静的束縛について調査することでstaticの知識の深まり、どのクラスがスコープになるのかがぼんやりした理解だったのが明らかになりました。ありがとうございました!

    キャンセル

+2

$name が private なので継承してオーバーライドしようとしても、元クラスのメソッドからは元クラスの $name にしかアクセス権がないため null になります。

キーワード アクセス権
private そのクラスからしかアクセスできない
protected そのクラスと、サブクラスからしかアクセスできない
public どこからでもアクセスできる

こういう場合には protected を使いましょう。

class User{
    protected $name = null;

    public function print_hello(){
        print $this->name;
        print "さん、こんにちは。";
    }
}

class Guest extends User{
    protected $name = "ゲスト";
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/30 22:29

    ご回答ありがとうございます。
    privateやprotectedの存在はテキストで見てはいたのですが、今一理解できていなかったんだなと感じました。

    キャンセル

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

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

関連した質問

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

  • PHP

    20318questions

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

  • オブジェクト指向

    284questions

    オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。