Как получить конструктор класса 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
}
}
Я знаю, что это странная вещь, и я пытаюсь найти средство, которое не пахнет плохо, но тем не менее, мне любопытно, если это возможно.
редактировать
Я подумал, что должен опубликовать обоснование выбранного ответа. Причина в том; это самое элегантное решение проблема с желанием вызвать конструктор "бабушки и дедушки", сохраняя при этом все значения. Это, конечно, не самый лучший подход, и он не является дружественным к ООП, но это не то, что спрашивал вопрос.
для тех, кто сталкивается с этим вопросом позже -пожалуйста, найдите другое решение. Я смог найти гораздо лучший подход, который не разрушал структуру класса. Так же как и ты.
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(); } }
Comments