У меня есть класс 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