Как мне получить конструктор класса 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();