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

I need to have a class constructor in PHP call its parent's parent's (grandparent?) constructor without calling the parent constructor.

// 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
    }
}

I know this is a bizarre thing to do and I'm attempting to find a means that doesn't smell bad but nonetheless, I'm curious if it's possible.

13.10.2009 00:09:04
Есть ли причина, по которой вы не можете просто создать экземпляр дедушки внутри конструкции Киддо?
Mark 13.10.2009 00:16:59
Конструктор Grampa устанавливает для себя свойства, которые наследуются его дочерними элементами. Папа делает в конструкторе кое-что, что испортит Киддо. Поэтому мне нужен вызов конструктора Grandpa, чтобы установить свойства для Kiddo во время строительства.
Paulo 13.10.2009 00:20:49
Тогда Киддо не должен простираться от дедушки, а не папы.
MitMaro 13.10.2009 00:26:26
@MitMaro. Я согласен, и я фактически решил свою настоящую проблему, создав промежуточный класс, который расширил дедушку. Затем и папа, и Киддо продлили этот класс. Kiddo требовал некоторой промежуточной функциональности Papa, но ему не нравился его конструктор, поэтому у класса есть эта дополнительная функциональность, и оба расширяют ее.
Paulo 13.10.2009 00:36:18
Идеальное решение. Вы должны опубликовать это как ответ.
MitMaro 13.10.2009 00:39:41
15 ОТВЕТОВ
РЕШЕНИЕ

Уродливый обходной путь - передать булеву параметру 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);
    }
}
164
13.10.2009 00:28:01
хороший обходной путь, но он неприемлем, если родительский класс происходит из какой-то внешней библиотеки, которую вы хотите расширить. Мне нравится слишком много ответов php ниже.
Kostanos 11.07.2013 15:26:56
Это на самом деле довольно умно. В моей реализации я делаю if($bypass) return;и могу расположить ее так, чтобы перед обходом были сделаны некоторые важные вещи.
Pedro 5.09.2019 08:09:17

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

77
13.10.2009 00:18:00
Can't understand how. Declaring __construct as static results in the following error for me "Fatal error: Constructor Grandpa::__construct() cannot be static" under PHP5.3
Mark 13.10.2009 04:08:29
When I tried it, I didn't declare it as static. I created the class structure normally but instead of calling parent::__construct(), I called Grandpa::__construct() and it worked. I doesn't seem right to me either but this whole question got kinda weird.
Paulo 13.10.2009 04:25:54
Согласовано. Я использую это все время - вы можете вызывать класс по его имени, а не только через магические имена parentили self. Я был известен, чтобы пройти три или четыре класса. На самом деле, я начал ссылаться на свой базовый класс по его имени, а не по родителю, так что я уверен, что всегда получаю нужный объект.
EvilChookie 9.11.2011 00:20:37
Слияние EvilChookie - лучшее. Должен быть одобренный ответ. Чем ты чоки!
nicksona 28.09.2016 13:21:35
В php, когда вы вызываете функцию с использованием статического оператора ::из контекста объекта, она вызывается с использованием контекста объекта, который полностью fkd-up. По крайней мере, в JS (о thisбезумии) он использует контекст вызываемого абонента.
SparK 4.10.2016 14:57:15

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

<?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";
16
13.10.2009 00:37:06

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

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

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

20
26.03.2013 14:37:03
Я думаю, что лучшая идея здесь состоит в том, чтобы разбить функциональность, которую вы пытаетесь использовать, из созданного и в защищенный метод. Затем вы можете вызывать этот метод из конструктора выборочно
xximjasonxx 14.06.2010 02:56:17
Это не отвечает на точный вопрос, который вы задали. Это происходит, если реальный мир запутывает что-то, что должно быть ясным и ограниченным. Жаль, что этот вопрос.
nalply 20.08.2012 08:17:52

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

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

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

Тогда в Kiddo вы используете:

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

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

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

2
3.12.2013 01:34:32

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

8
14.06.2010 02:39:09
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();
    }
}
54
18.01.2012 11:51:06
Лично я бы не стал этого делать, так как это означает, что подрядчику Папы вообще не позвонят. Я бы пошел с чем-то вроде подхода cballou (то есть передачи аргумента конструктору Papa и вызова его родительским конструктором или не основанного на этом).
Iain Collins 6.04.2012 23:42:19
Ситуация, в которой мы находимся здесь, такова, что нам нужно пропустить логику родителя, и в большинстве случаев мы не можем изменить прародителя или родительские классы. Я считаю, что это лучший способ сделать это, поскольку есть изменения, сделанные только в ребенке. Единственная проблема заключается в том, что он может выдать ссылку на уведомление E_STRICT , но не для меня, когда я ее тестировал.
mimarcel 15.07.2013 10:06:56
Это интересное решение, однако, если вам действительно не нужна логика конструктора родителя, вы уверены, что действительно делаете подкласс родителя?
v010dya 26.12.2017 14:22:07
This is the correct answer. While it may seem silly to inherit Papa but you want to call the GrandPa constructor without Papa, I've found it useful to be do. I want to keep the hierarchy, but I need to do a clean Kiddo constructor that doesn't have anything to do with Papa, but still want the benefits of using what's going on in GrandPa's constructor. Maybe Papa is doing a bunch of junk in the constructor that isn't needed or wanted by Kiddo, but it still has useful components.
Halfstop 13.03.2018 18:24:38

Вы можете вызвать конструкцию 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's constructor
        parent::__construct();
    }
}

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

new Kiddo();
7
9.12.2012 19:51:18
// 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».

1
10.05.2013 09:17:39

I agree with "too much php", try this:

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;

I got the result as expected:

Kiddo

Grandpa

This is a feature not a bug, check this for your reference:

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

It is just the way it works. If it sees it is coming from the right context this call version does not enforce a static call.

Instead it will simply keep $this and be happy with it.

parent::method() works in the same way, you don't have to define the method as static but it can be called in the same context. Try this out for more interesting:

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;

It also works as expected:

Kiddo

Grandpa

Hello

But if you try to initialize a new Papa, you will get an E_STRICT error:

$papa = new Papa;

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

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

if ($this instanceof Kiddo) Kiddo::hello();
9
18.09.2013 03:14:35
Just remember that parent is only a shortcut to whatever first parent that implemented the method… Thus from a descendant calling AscendantName::method works and from an ascendant calling static::method will always call the latest generation that implemented the method. And you may check not to call yourself using (get_class($this)==__CLASS__?'Healthy people dont\'t call themself…':'Calling latest') if you'd like parents to call kid methods (seems strange but might be usefull combined with private function and __call magic function )…
llange 30.10.2015 21:44:46
<?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();
?>

Of course this expects you do not need to do anything within the construct of the pa_pa. Running this will output :

Hey I am Grand Pa Hey I am a child

2
18.07.2014 03:39:41

Beautiful solution using 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();
22
22.03.2015 15:57:26
    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();
    }
}
1
26.08.2015 16:56:44

Funny detail about php: extended classes can use non-static functions of a parent class in a static matter. Outside you will get a strict error.

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 

So inside a extended class (Child) you can use

parent::paFkt(); 

or

Pa::paFkt();

to access a parent (or grandPa's) (not private) function.

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

$test::paFkt();

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

4
4.03.2016 11:59:24

с PHP 7 вы можете использовать

parent::parent::__construct();

-3
10.07.2017 15:59:32
@ Wouter0100 lala977 сказал «Из PHP 7», который использует ваша ссылка 5.6
Travis Weston 12.01.2018 17:56:27
@TravisWeston, пожалуйста, перепроверьте мою ссылку. это проверяет это спокойствие кода против всех версий. 5.6 до 7.2 воспроизводят ту же ошибку, в то время как другие среды выполнения возвращают некоторые другие ошибки.
Wouter0100 12.01.2018 21:47:02