Programming

PHP 클래스 생성자가 부모의 부모 생성자를 호출하도록하려면 어떻게해야합니까?

procodes 2020. 5. 12. 20:20
반응형

PHP 클래스 생성자가 부모의 부모 생성자를 호출하도록하려면 어떻게해야합니까?


PHP에서 클래스 생성자가 부모 생성자를 호출하지 않고 부모의 부모 (조부모?) 생성자를 호출해야합니다.

// main class that everything inherits
class Grandpa 
{
    public function __construct()
    {

    }

}

class Papa extends Grandpa
{
    public function __construct()
    {
        // call Grandpa's constructor
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public function __construct()
    {
        // THIS IS WHERE I NEED TO CALL GRANDPA'S
        // CONSTRUCTOR AND NOT PAPA'S
    }
}

나는 이것이 기괴한 일이라는 것을 알고 있으며, 나쁘지 않지만 냄새가 나는 방법을 찾으려고 노력하고 있습니다. 가능하다면 궁금합니다.


추악한 해결 방법은 부울 매개 변수를 Papa에 전달하여 생성자에 포함 된 코드를 구문 분석하지 않으려는 것을 나타냅니다. 즉 :

// main class that everything inherits
class Grandpa 
{
    public function __construct()
    {

    }

}

class Papa extends Grandpa
{
    public function __construct($bypass = false)
    {
        // only perform actions inside if not bypassing
        if (!$bypass) {

        }
        // call Grandpa's constructor
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public function __construct()
    {
        $bypassPapa = true;
        parent::__construct($bypassPapa);
    }
}

를 사용해야 Grandpa::__construct()합니다. 다른 단축키는 없습니다. 또한 이것은 Papa클래스 의 캡슐화를 망칩니다 -읽거나 작업 할 때 메소드가 생성 중에 호출 될 Papa것이라고 가정하는 것이 안전해야 __construct()하지만 Kiddo클래스는 이것을하지 않습니다.


class Grandpa 
{
    public function __construct()
    {}
}

class Papa extends Grandpa
{
    public function __construct()
    {
        //call Grandpa's constructor
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public function __construct()
    {
        //this is not a bug, it works that way in php
        Grandpa::__construct();
    }
}

를 사용하는 아름다운 솔루션 Reflection.

<?php
class Grandpa 
{
    public function __construct()
    {
        echo "Grandpa's constructor called\n";
    }

}

class Papa extends Grandpa
{
    public function __construct()
    {
        echo "Papa's constructor called\n";

        // call Grandpa's constructor
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public function __construct()
    {
        echo "Kiddo's constructor called\n";

        $reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($this)), '__construct');
        $reflectionMethod->invoke($this);
    }
}

$kiddo = new Kiddo();
$papa = new Papa();

결국 문제를 해결 한 대체 솔루션을 찾았습니다.

  • 할아버지를 확장하는 중급 클래스를 만들었습니다.
  • 그런 다음 Papa와 Kiddo는 모두 그 수업을 확장했습니다.
  • Kiddo는 Papa의 중간 기능이 필요했지만 생성자가 마음에 들지 않아 클래스에 추가 기능이 있으며 둘 다 확장했습니다.

나는 추악한 질문에 대해 유효하지만 추악한 해결책을 제공하는 다른 두 가지 대답을 찬성했습니다.)


플래그를 사용하지 않고 상황에 따라 작동하는 다른 옵션 :

<?php
// main class that everything inherits
class Grandpa 
{
    public function __construct(){
        $this->GrandpaSetup();
    }

    public function GrandpaSetup(){
        $this->prop1 = 'foo';
        $this->prop2 = 'bar';
    }
}

class Papa extends Grandpa
{
    public function __construct()
    {
        // call Grandpa's constructor
        parent::__construct();
        $this->prop1 = 'foobar';
    }

}
class Kiddo extends Papa
{
    public function __construct()
    {
        $this->GrandpaSetup();
    }
}

$kid = new Kiddo();
echo "{$kid->prop1}\n{$kid->prop2}\n";

"너무 많은 PHP"에 동의합니다.

class Grandpa 
{
    public function __construct()
    {
        echo 'Grandpa<br/>';
    }

}

class Papa extends Grandpa
{
    public function __construct()
    {
        echo 'Papa<br/>';
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public function __construct()
    {
        // THIS IS WHERE I NEED TO CALL GRANDPA'S
        // CONSTRUCTOR AND NOT PAPA'S
        echo 'Kiddo<br/>';
        Grandpa::__construct();
    }
}

$instance = new Kiddo;

예상대로 결과를 얻었습니다.

키도

할아버지

이것은 버그가 아닌 기능이므로 참조를 위해 확인하십시오.

https://bugs.php.net/bug.php?id=42016

그것은 작동하는 방식입니다. 올바른 컨텍스트에서 오는 것으로 확인되면이 호출 버전은 정적 호출을 시행하지 않습니다.

대신 단순히 $ this를 유지하고 만족합니다.

parent :: method ()는 동일한 방식으로 작동하므로 메소드를 정적으로 정의 할 필요는 없지만 동일한 컨텍스트에서 호출 할 수 있습니다. 더 흥미롭게 이것을 시도하십시오 :

class Grandpa 
{
    public function __construct()
    {
        echo 'Grandpa<br/>';
        Kiddo::hello();
    }

}

class Papa extends Grandpa
{
    public function __construct()
    {
        echo 'Papa<br/>';
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public function __construct()
    {
        // THIS IS WHERE I NEED TO CALL GRANDPA'S
        // CONSTRUCTOR AND NOT PAPA'S
        echo 'Kiddo<br/>';
        Grandpa::__construct();
    }

    public function hello()
    {
        echo 'Hello<br/>';
    }
}

$instance = new Kiddo;

예상대로 작동합니다.

키도

할아버지

여보세요

그러나 새 Papa를 초기화하려고하면 E_STRICT 오류가 발생합니다.

$papa = new Papa;

엄격한 표준 : 비 정적 메소드 Kiddo :: hello ()는 $ this를 호환되지 않는 컨텍스트에서 가정하면 정적으로 호출해서는 안됩니다.

instanceof를 사용하여 부모 메서드에서 Children :: method ()를 호출 할 수 있는지 확인할 수 있습니다.

if ($this instanceof Kiddo) Kiddo::hello();

더 쉬운 해결책이 있지만 현재 클래스가 얼마나 많은 상속을 받았는지 정확하게 알아야합니다. 다행스럽게도 get_parent_class ()의 인수를 사용하면 클래스 배열 멤버가 인스턴스뿐만 아니라 문자열의 클래스 이름이 될 수 있습니다.

상속하는 객체의 인스턴스 범위 내 에서이 특별한 경우의 차이는 무시할 수 있지만 (ah, PHP), 이것은 본질적으로 클래스의 __construct () 메소드를 정적으로 호출하는 것에 의존한다는 것을 명심하십시오.

다음을 고려하세요:

class Foo {
    var $f = 'bad (Foo)';

    function __construct() {
        $this->f = 'Good!';
    }
}

class Bar extends Foo {
    var $f = 'bad (Bar)';
}

class FooBar extends Bar {
    var $f = 'bad (FooBar)';

    function __construct() {
        # FooBar constructor logic here
        call_user_func(array(get_parent_class(get_parent_class($this)), '__construct'));
    }
}

$foo = new FooBar();
echo $foo->f; #=> 'Good!'

다시 말하지만, 이것은 debug_backtrace ()의 한계로 인해 얼마나 많은 상속이 발생했는지 알지 못하는 상황에서는 실행 가능한 솔루션이 아니지만 통제 된 환경에서는 의도 한대로 작동합니다.


원하는 곳에서 Grandpa :: __ construct를 호출하면 $ this 키워드가 현재 클래스 인스턴스를 참조합니다. 그러나이 방법을 사용하면이 다른 컨텍스트에서 현재 인스턴스의 보호 된 속성 및 메서드에 액세스 할 수 없으며 공용 요소에만 액세스 할 수 없습니다. => 모든 업무와 공식 지원 .

// main class that everything inherits
class Grandpa 
{
    public function __construct()
    {
        echo $this->one; // will print 1
        echo $this->two; // error cannot access protected property
    }

}

class Papa extends Grandpa
{
    public function __construct()
    {
        // call Grandpa's constructor
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public $one = 1;
    protected $two = 2;
    public function __construct()
    {
        Grandpa::__construct();
    }
}

new Kiddo();

PHP에 대한 재미있는 세부 사항 : 확장 클래스는 정적 문제에서 부모 클래스의 비 정적 함수를 사용할 수 있습니다. 외부에서는 엄격한 오류가 발생합니다.

error_reporting(E_ALL);

class GrandPa
{
    public function __construct()
    {
        print("construct grandpa<br/>");
        $this->grandPaFkt();
    }

    protected function grandPaFkt(){
        print(">>do Grandpa<br/>");
    }
}

class Pa extends GrandPa
{
    public function __construct()
    {   parent::__construct();
        print("construct Pa <br/>");
    }

    public function paFkt(){
        print(">>do Pa <br>");
    }
}

class Child extends Pa
{
    public function __construct()
    {
        GrandPa::__construct();
        Pa::paFkt();//allright
        //parent::__construct();//whatever you want
        print("construct Child<br/>");
    }

}

$test=new Child();
$test::paFkt();//strict error 

확장 클래스 (자식) 안에서 사용할 수 있습니다.

parent::paFkt(); 

또는

Pa::paFkt();

부모 (또는 할아버지) (비공개) 기능에 액세스합니다.

외부 클래스 데프

$test::paFkt();

엄격한 오류가 발생하지 않습니다 (정적 기능이 아님).


좋아, 또 다른 추악한 해결책 :

Papa에서 다음과 같은 함수를 작성하십시오.

protected function call2Granpa() {
     return parent::__construct();
}

그런 다음 Kiddo에서 다음을 사용합니다.

parent::call2Granpa(); // Papa에서 생성자를 호출하는 대신.

나는 그것이 효과가 있다고 생각합니다 ... 테스트하지 않았으므로 객체가 올바르게 생성되었는지 확실하지 않습니다.

이 접근 방식을 사용했지만 생성자가 아닌 함수를 사용했습니다.


<?php

class grand_pa
{
    public function __construct()
    {
        echo "Hey I am Grand Pa <br>";
    }
}

class pa_pa extends grand_pa
{
    // no need for construct here unless you want to do something specifically within this class as init stuff
    // the construct for this class will be inherited from the parent.
}

class kiddo extends pa_pa
{
    public function __construct()
    {
        parent::__construct();
        echo "Hey I am a child <br>";
    }
}

new kiddo();
?>

물론 이것은 pa_pa의 구조 내에서 아무것도 할 필요가 없습니다. 이것을 실행하면 다음이 출력됩니다.

안녕하세요, Grand Pa입니다 안녕하세요, 저는 아이입니다


// main class that everything inherits
class Grandpa 
{
    public function __construct()
    {
        $this->___construct();
    }

    protected function ___construct()
    {
        // grandpa's logic
    }

}

class Papa extends Grandpa
{
    public function __construct()
    {
        // call Grandpa's constructor
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public function __construct()
    {
        parent::___construct();
    }
}

"___construct"는 마법 이름이 아니며 "doGrandpaStuff"라고 부를 수 있습니다.


    class Grandpa 
{
    public function __construct()
    {
        echo"Hello Kiddo";
    }    
}

class Papa extends Grandpa
{
    public function __construct()
    {            
    }
    public function CallGranddad()
    {
        parent::__construct();
    }
}

class Kiddo extends Papa
{
    public function __construct()
    {

    }
    public function needSomethingFromGrandDad
    {
       parent::CallGranddad();
    }
}

PHP 7에서 u는 사용할 수 있습니다

parent::parent::__construct();

참고 : https://stackoverflow.com/questions/1557608/how-do-i-get-a-php-class-constructor-to-call-its-parents-parents-constructor

반응형