2016-08-20 6 views
2

私はクラススコープが異なるオブジェクトのプライベートプロパティとプロテクトプロパティへのアクセスにどのように影響するかを理解しようとしています。親クラスのコンテキストで子クラスのプライベートプロパティにアクセスしようとすると、何か変なものが見つかりました。子クラスのプライベートプロパティへのアクセス

ここはコード例です。メソッドをプロパティに置き換えると、まったく同じ動作を確認できます。

class ParentClass{ 
    public function test($childObj){ 
     $childObj->getProtected(); 
     $childObj::getProtected(); 
     $childObj->getPrivate(); 
     $childObj::getPrivate(); 
    } 
    private function getPrivate(){ 
     echo "ParentClass private"; 
    } 
    protected function getProtected(){ 
     echo "ParentClass protected"; 
    } 
} 
class ChildClass extends ParentClass{ 
    private function getPrivate(){ 
     echo "ChildClass private"; 
    } 
    protected function getProtected(){ 
     echo "ChildClass protected"; 
    } 
} 
(new ParentClass)->test(new ChildClass()); 

出力:

ChildClass protected 
ChildClass protected (and E_DEPRICATED error) 
ParentClass private 
Fatal error: Call to private ChildClass::getPrivate() from context 'ParentClass' 

まあ、最初の2つの出力のイム罰金。私はそれがドキュメントのどこかで言及されていると思います。親のコンテキストでは、子クラスの保護されたメソッド/プロパティにアクセスできます。しかしプライベートについてはどうですか? 3番目の出力でParentClassメソッドに戻り、4番目にエラーがスローされるのはなぜですか?

+1

あるクラスインスタンスを使用して別のクラスインスタンスの値にアクセスして、意図的に継承を破ろうとしていますか?これは実際のコーディングではあまり現実的ではありません –

+0

なぜスコープ解決 '::'演算子を持つクラスの非静的メソッドを呼び出すのですか? – Kamran

+0

マーク・ベイカー、そうです、あなたが正しいと思います。私は実際に何をしようとしているのかわかりません、私はOOPについてのいくつかの本を読んでいました。そして、それは私のやり方です。私が何かを読んだとき、私はいつも自分に尋ねます。「もし私が好きなら、どうしたらいいでしょうか」:/ –

答えて

3

これは興味深い質問ですので、私は小さな研究を掘り下げました。実際にあなたが作る呼び出しのいくつかはドキュメントに従って動作しますが、実生活ではまれであり、文書化されていないものもありますので、それらをPHP実装の詳細として扱うことができます。

最初に、非通知メソッドで::演算子を使用しないでください。これは、PHP通知では非推奨の動作です。

したがって、テストを2つの別々のテストに分割しましょう.1つは非静的メソッド用、もう1つは静的メソッド用です。ここ は非静的メソッドのテストです:

class ParentClass{ 
    public function test($childObj){ 
     $childObj->getProtected(); 
     $childObj->getPrivate(); 
    } 
    private function getPrivate(){ 
     echo "ParentClass private"; 
    } 
    protected function getProtected(){ 
     echo "ParentClass protected"; 
    } 
} 

class ChildClass extends ParentClass{ 
    private function getPrivate(){ 
     echo "ChildClass private"; 
    } 
    protected function getProtected(){ 
     echo "ChildClass protected"; 
    } 
} 

(new ParentClass)->test(new ChildClass()); 

それは出力:

ChildClass protected

ParentClass private

そして、ここではphp documentationから関連する部分である:延期の場合

Objects of the same type will have access to each others private and protected members even though they are not the same instances. This is because the implementation specific details are already known when inside those objects.

$childObj->getProtected(); - $childObjParentClassのサブタイプであるため、同じタイプのオブジェクトとして扱うことができます。 は、そこでここでは、次のとおりです。

  1. getProtected()方法
  2. このメソッドの呼び出しParentClassタイプ
  3. のものとして$childObj変数の治療に保護されているので、継承ルールが適用され、私たちは、子クラスの実装を呼び出す
  4. "ChildClass protected"出力が得られます

私たちがpriで同じことをしようとするとvateメソッドでは、まだ$childObj->getPrivate()を呼び出すことができますが、継承を介してプライベートメンバー/メソッドを使用することはできないため、継承ルールは適用されません。この時点で私たちは、次のとおりです。

  1. は、それがプライベートなので、継承ルールが適用されません
  2. getPrivate()メソッドを呼び出すParentClassタイプに
  3. であるとして$childObj変数を扱う(ただし、この言語の実装の詳細、下記参照)、我々は我々が静的メソッドメソッドたちのための「ParentClassプライベート」出力

を取得

  • ParentClassの実装を呼び出しますインスタンスレベルではなくクラスレベルのメソッドを呼び出すので、継承ルールはここでは適用できません。

    私は、我々がこのよう静的呼び出しのためのコードを記述する場合は(私たちは本当にオブジェクトのインスタンスを必要としない、我々はクラス名のみを必要とする)明確だと思う:

    class ParentClass{ 
        public static function test() { 
         ChildClass::getProtected(); 
         ChildClass::getPrivate(); 
        } 
    } 
    
    class ChildClass extends ParentClass{ 
        private static function getPrivate(){ 
         echo "ChildClass private"; 
        } 
        protected static function getProtected(){ 
         echo "ChildClass protected"; 
        } 
    } 
    (new ParentClass)->test(); 
    

    それが出力されます。

    ChildClass protected

    PHP Fatal error: Uncaught Error: Call to private method ChildClass::getPrivate() from context 'ParentClass'

    私は、2番目の呼び出しでエラーが発生するのは明らかです。別のクラスのprivate staicメソッドを呼び出そうとしています。

    最初の呼び出しであるChildClass::getProtected()が動作する理由はもっと面白いです。他のクラスの保護されたメソッドを呼び出そうとしており、継承ルールはここでは適用しないでください。

    唯一の説明は、言語の実装の詳細です。 私はこの保護されたメソッド呼び出しは本当に動作しないはずだと思います。

    私もここで私がthe first testのために得るものである、C++にこれを比較してみました:

    #include <iostream> 
    using namespace std; 
    
    class ParentClass { 
        public: 
         void test(ParentClass* obj); 
        protected: 
         virtual void getProtected(); 
        private: 
         virtual void getPrivate(); 
    }; 
    
    class ChildClass: public ParentClass{ 
        protected: 
         virtual void getProtected(); 
        private: 
         virtual void getPrivate(); 
    }; 
    
    
    //private virtual 
    void ParentClass::getPrivate(){ 
        cout << "ParentClass private"; 
    } 
    //protected virtual 
    void ParentClass::getProtected(){ 
        cout << "ParentClass protected"; 
    } 
    //public 
    void ParentClass::test(ParentClass* obj) { 
        obj->getProtected(); 
        obj->getPrivate(); 
    }; 
    
    //private virtual 
    void ChildClass::getPrivate(){ 
        cout << "ChildClass private"; 
    } 
    //protected virtual 
    void ChildClass::getProtected(){ 
        cout << "ChildClass protected"; 
    } 
    
    int main() { 
        cout << "test"; 
        (new ParentClass)->test(new ChildClass); 
    } 
    

    そして、それは出力:

    test

    ChildClass protected

    ChildClass private

    だから、違ったPHPでよりプライベートな方法のために働きますC++はprivateメソッドの場合でも実際に子クラスの実装を呼び出します。静的メソッドの

    第二の試験は:

    #include <iostream> 
    using namespace std; 
    
    class ParentClass { 
        public: 
         static void test(); 
    }; 
    
    class ChildClass: public ParentClass{ 
        protected: 
         static void getProtected(); 
        private: 
         static void getPrivate(); 
    }; 
    
    //public static 
    void ParentClass::test() { 
        // error: 'static void ChildClass::getProtected()' is protected 
        //ChildClass::getProtected(); 
        // error: 'static void ChildClass::getPrivate()' is private 
        //ChildClass::getPrivate(); 
    }; 
    
    //private static 
    void ChildClass::getPrivate(){ 
        cout << "ChildClass private"; 
    } 
    //protected static 
    void ChildClass::getProtected(){ 
        cout << "ChildClass protected"; 
    } 
    
    
    int main() { 
        cout << "test"; 
        (new ParentClass)->test(); 
    } 
    

    どちらも保護され、民間の呼び出しは、ここでは動作しません。これらの呼び出しでは、プログラムをコンパイルすることすらできません。

    これは、PHPで保護された静的メソッドを呼び出すことができるよりも論理的だと思います。

  • +1

    クール。ありがとうございました –

    関連する問題