Как получить конструктор класса 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
}
}


Я знаю, что это странная вещь, и я пытаюсь найти средство, которое не пахнет плохо, но тем не менее, мне любопытно, если это возможно.



редактировать



Я подумал, что должен опубликовать обоснование выбранного ответа. Причина в том; это самое элегантное решение проблема с желанием вызвать конструктор "бабушки и дедушки", сохраняя при этом все значения. Это, конечно, не самый лучший подход, и он не является дружественным к ООП, но это не то, что спрашивал вопрос.



для тех, кто сталкивается с этим вопросом позже -пожалуйста, найдите другое решение. Я смог найти гораздо лучший подход, который не разрушал структуру класса. Так же как и ты.

779   15  

15 ответов:

уродливым обходным путем было бы передать логический параметр папе, указывающий, что вы не хотите анализировать код, содержащийся в его конструкторе. я.е:

// 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();
    }
}

Я в конечном итоге придумал альтернативное решение, которое решило проблему.

  • Я создал промежуточный класс, который продлен дедушка.
  • затем и папа, и малыш расширили этот класс.
  • 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";

красивое решение с помощью 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();

есть более простое решение для этого, но оно требует, чтобы вы точно знали, сколько наследования прошел ваш текущий класс. К счастью, аргументы get_parent_class () позволяют члену массива класса быть именем класса в виде строки, а также самим экземпляром.

имейте в виду, что это по своей сути полагается на вызов класса-метод __Construct() метод статически, хотя в приведенных объем наследуемого объекта Разница в данном конкретном случае ничтожно мало (ах, PHP).

рассмотрим следующее:

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 (), но в контролируемых обстоятельствах он работает по назначению.

Я согласен с "слишком много 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;

Он также работает, как ожидалось:

деточка

дедушка

Привет

но если вы попытаетесь инициализировать новый папа, вы получите ошибку E_STRICT:

$papa = new Papa;

строгие стандарты: нестатический метод Kiddo:: hello () не должен вызываться статически, предполагая $this из несовместимого контекста

вы можете использовать instanceof, чтобы определить, можно ли вызвать Children:: method () в Родительском методе:

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

вы можете вызвать 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();

для доступа к родительской (или дедушкиной) (не частной) функции.

вне класса def

$test::paFkt();

будет trow строгая ошибка (не статическая функция).

ок, еще одно уродливое решение:

создать функцию в папу:

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. Запуск этого будет выводить:

Эй, я великий па Эй, я ребенок

// 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 Вы можете использовать

parent::parent::__construct();

Comments

    Ничего не найдено.