Как мне получить конструктор класса PHP для вызова родительского родительского конструктора?

Мне нужно, чтобы конструктор класса в PHP вызывал его родительский конструктор parent (grandparent?) Без вызова родительского конструктора.

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

    }

}

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

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

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

Ответ 1

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

// 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 constructor
        parent::__construct();
    }
}

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

Ответ 2

Вы должны использовать Grandpa::__construct(), для этого нет другого ярлыка. Кроме того, это разрушает инкапсуляцию класса Papa - при чтении или работе с Papa, должно быть безопасно предположить, что метод __construct() будет вызываться во время построения, но класс Kiddo не делает этого.

Ответ 3

class Grandpa 
{
    public function __construct()
    {}
}

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

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

Ответ 4

Красивое решение с помощью Reflection.

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

}

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

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

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

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

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

Ответ 5

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

  • Я создал промежуточный класс, который расширил дедушку.
  • Затем оба Папа и Киддо расширили этот класс.
  • Kiddo потребовал некоторых промежуточных функциональных возможностей Papa, но не понравился конструктор, поэтому класс обладает дополнительными функциональными возможностями и расширяет его.

Я поддержал два других ответа, которые предоставили правильные и уродливые решения для более уродливого вопроса:)

Ответ 6

Другой вариант, который не использует флаг и может работать в вашей ситуации:

<?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 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";

Ответ 7

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

Я получил результат, как ожидалось:

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;

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

Kiddo

     

Дедушка

     

Hello

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

$papa = new Papa;

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

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

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

Ответ 8

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

Ответ 9

Вы можете вызвать конструкцию Grandpa:: __, где хотите, и $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 constructor
        parent::__construct();
    }
}

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

new Kiddo();

Ответ 10

Забавные подробности о 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 

Итак, внутри расширенного класса (Child) вы можете использовать

parent::paFkt(); 

или

Pa::paFkt();

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

Внешний класс def

$test::paFkt();

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

Ответ 11

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

Создайте функцию в папке, например:

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

Затем в Kiddo вы используете:

parent::call2Granpa();//вместо вызова конструктора в папке.

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

Я использовал этот подход, но с неконструкторскими функциями.

Ответ 12

<?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. Запустим это:

Эй, я Великая Па Эй, я ребенок

Ответ 13

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

    protected function ___construct()
    {
        // grandpa logic
    }

}

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

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

Обратите внимание, что "___construct" не является каким-то магическим именем, вы можете называть его "doGrandpaStuff".

Ответ 14

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

Ответ 15

из php 7 u можно использовать

parent::parent::__construct();