У меня есть класс PHP класса, называемый ClassA, который расширен многими другими классами рисования, например ClassB .
Мне нужны унаследованные классы, чтобы запустить метод родительских классов Draw () . Однако в моей конкретной ситуации я не хочу напрямую обращаться к такому методу (например: parent::Draw()
). Мне parent::InvokeDraw()
третья функция (например: parent::InvokeDraw()
) для вызова моего метода рисования из контекста родителя.
Вот несколько примеров для иллюстрации:
class ClassA { function Draw() { /* Drawing code ... */ } function InvokeDraw() { $this->Draw(); } } class ClassB extends ClassA { function Draw() { parent::InvokeDraw(); /* Drawing code ... */ } }
Проблема, с которой я сталкиваюсь, заключается в том, что InvokeDraw () не будет вызывать метод Draw () родителя, а скорее метод Draw Draw () расширенного класса, что вызывает бесконечный цикл.
Хотя проблема довольно логична, мне сложно найти решение обходного пути. Как выполнить эту задачу?
Этот метод использует статические методы
<?php class ClassA { function Draw() { echo "DrawA"; /* Drawing code ... */ } function InvokeDraw() { self::Draw(); } } class ClassB extends ClassA { function Draw() { echo "DrawB"; parent::InvokeDraw(); /* Drawing code ... */ } } echo "Begin:<br>"; $cb = new ClassB(); $cb->Draw();
Обратите внимание, что единственное, что я изменил, это метод InvokeDraw()
и заставил его использовать self
который ссылается на класс, а не на объект, как на $this
Вывод:
Begin: DrawBDrawA
Изменить: Чтобы ответить на ваш комментарий ниже, я добавлю краткое описание того, как работает ваш код и как работает этот код.
Что происходит в вашем коде:
B
и начинаем работать с ним B->Draw()
во время работы внутри объекта B
класса AND B
B->Draw()
вызывает статически (это означает метод класса) A::Invoke()
из класса A, но мы все еще используем объект B
A::Invoke()
вызывает $this->Draw();
и поскольку мы работаем в настоящее время с объектом B
, $this
относится к экземпляру ClassB
. Что происходит в коде выше:
B
и начинаем работать с ним B->Draw()
во время работы внутри объекта B
класса AND B
B->Draw()
вызывает статически (это означает метод класса) A::Invoke
из класса A, но как и в вашем коде, мы все еще используем объект B
A::Invoke()
вызывает self::Draw()
который в основном такой же, как ClassA::Draw()
и поскольку это статический метод, нам не важно, с каким объектом мы в настоящее время работаем, и называем Метод A
' Draw()
. A::Draw()
выполняется по мере необходимости. В моем втором ответе я дам такое же объяснение для кода, который не использует статические вызовы:
B
и начинаем работать с ним B->Draw()
во время работы внутри объекта B
класса AND B
B->Draw()
СОЗДАЕТ экземпляр A
B->Draw()
вызывает A->Invoke()
что означает, что мы начинаем работать с объектом, являющимся экземпляром класса A
а не B
как раньше. На этом этапе мы полностью забываем, что B
даже существует и работает только с A
A->Invoke()
вызывает $this->Draw()
что означает, что мы вызываем A->Draw()
, потому что мы уже работаем с экземпляром класса A
A->Draw()
выполняется, как мы ожидаем. С точки зрения удобства использования мы видим, что статический метод лучше, так как мы можем определить некоторые статические свойства, и вы можете работать с ними, когда выполняется A::Draw()
. Если мы используем нестатический метод, нам нужно передать нужные данные в аргументах наших методов.
Надеюсь, это ясно. Вышеупомянутые последовательности не имеют правильной терминологии, но это было написано специально, я думаю, что легче понять поток таким образом.
На поверхностном уровне наследование работает как слияние кода. Наследуемые методы являются частью дочернего класса, как если бы они были родными для класса:
class A { public function foo() { echo 'foo'; } public function bar() { echo 'bar'; } } class B extends A { }
Для всех целей и целей это эквивалентно написанию:
class B { public function foo() { echo 'foo'; } public function bar() { echo 'bar'; } }
Класс B
имеет функцию foo
и bar
как если бы они были частью его объявления.
Переопределение методов в дочернем классе заменяет одну конкретную реализацию другой:
class B extends A { public function bar() { echo 'baz'; } }
Это как если бы B
был объявлен следующим образом:
class B { public function foo() { echo 'foo'; } public function bar() { echo 'baz'; } }
За одним исключением: реализация родителем метода доступна с использованием parent
ключевого слова. Он не меняет контекста, в котором выполняется код, просто использует реализацию родителя метода:
class B extends A { public function bar() { public function bar() { parent::bar(); ---> echo 'bar'; } } }
Он работает в том же контексте текущего экземпляра B
, он просто вытаскивает старый код родителя из эфира.
Если вы вызываете другой метод в методе родителя, он выполняется в контексте дочернего элемента, а не в контексте родительского класса. Поскольку вы не создали экземпляр родителя, вы работаете с ребенком. Чтобы продемонстрировать со свойствами (он работает одинаково с методами):
class A { protected $value = 'bar'; public function bar() { echo $this->value; } } class B extends A { protected $value = 'baz'; public function bar() { parent::bar(); // outputs "baz" echo $this->value; // outputs "baz" } }
Таким образом, нет решения вашей проблемы. Вы не можете вызвать метод в «контексте родителя». Вы можете вызвать код родителя в текущем контексте, вот и все. То, что вы создаете, – это простой цикл, потому что неважно, наследуется ли код или нет, все работает в одном контексте.
Вам нужно перепроектировать этот класс, чтобы не вызывать методы в цикле.
Как сказал deceze, нет решения вашей проблемы, если вы не перепроектируете класс.
Если вы используете PHP 5.4, вы можете использовать Traits .
Создайте 2 черты, каждая из которых имеет свою собственную функцию Draw
. Затем используйте один признак в родительском, а другой – в дочернем.
Затем, чтобы получить доступ к родительской функции от дочернего InvokeDraw
, установите псевдоним InvokeDraw
в родительскую функцию Draw
.
Вот пример:
<?php trait DrawingA { function Draw() { echo 'I am the parent'; } } trait DrawingB { function Draw() { echo 'I am the child'; } } class ClassA { use DrawingA; } class ClassB extends ClassA { use DrawingA, DrawingB { DrawingB::Draw insteadof DrawingA; DrawingA::Draw as InvokeDraw; } } $b = new ClassB(); echo 'Child: ', $b->Draw(), PHP_EOL; echo 'Parent: ', $b->InvokeDraw() . PHP_EOL; /* Outputs: Child: I am the child Parent: I am the parent */
Мне очень понравился ваш вопрос, так что я немного изучил и попытался сделать то же самое, что и в своем первом ответе, но без статических вызовов:
<?php class ClassA { function Draw() { echo "DrawA"; /* Drawing code ... */ } function InvokeDraw() { $this->Draw(); } } class ClassB extends ClassA { function Draw() { echo "DrawB"; $x = new parent; $x->InvokeDraw(); /* Drawing code ... */ } } echo "Begin:<br>"; $cb = new ClassB(); $cb->Draw();
Вывод:
Begin: DrawBDrawA