PHP: как вызвать функцию дочернего класса из родительского класса

Как вызвать функцию дочернего класса из родительского класса? Учти это:

class whale { function __construct() { // some code here } function myfunc() { // how do i call the "test" function of fish class here?? } } class fish extends whale { function __construct() { parent::construct(); } function test() { echo "So you managed to call me !!"; } } 

Solutions Collecting From Web of "PHP: как вызвать функцию дочернего класса из родительского класса"

Для этого нужны абстрактные классы . Абстрактный класс в основном говорит: «Кто наследует меня, должен иметь эту функцию (или эти функции).

 abstract class whale { function __construct() { // some code here } function myfunc() { $this->test(); } abstract function test(); } class fish extends whale { function __construct() { parent::__construct(); } function test() { echo "So you managed to call me !!"; } } $fish = new fish(); $fish->test(); $fish->myfunc(); 

Хорошо, этот ответ ОЧЕНЬ поздний, но почему никто не подумал об этом?

 Class A{ function call_child_method(){ if(method_exists($this, 'child_method')){ $this->child_method(); } } } 

И метод определен в расширяющемся классе:

 Class B extends A{ function child_method(){ echo 'I am the child method!'; } } 

Итак, со следующим кодом:

 $test = new B(); $test->call_child_method(); 

Выход будет:

 I am a child method! 

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

Технически вы не можете вызвать экземпляр рыбы (ребенка) из экземпляра кита (родителя), но поскольку вы имеете дело с наследованием, myFunc () будет доступен в вашем экземпляре рыбы в любом случае, так что вы можете вызвать $yourFishInstance->myFunc() непосредственно.

Если вы ссылаетесь на шаблон метода шаблона , просто напишите $this->test() как тело метода. Вызов myFunc() из экземпляра рыбы делегирует вызов test() в экземпляре рыбы. Но опять же, нет вызова от экземпляра кита к экземпляру рыбы.

На сиднейте кит – это млекопитающее, а не рыба;)

Хорошо, ну так много чего не так с этим вопросом, я не знаю, с чего начать.

Во-первых, рыба – это не киты, а киты – не рыба. Киты – это млекопитающие.

Во-вторых, если вы хотите вызвать функцию в дочернем классе из родительского класса, который не существует в вашем родительском классе, ваша абстракция серьезно испорчена, и вы должны пересмотреть ее с нуля.

В-третьих, в PHP вы можете просто сделать:

 function myfunc() { $this->test(); } 

В случае whale это вызовет ошибку. В случае с fish он должен работать.

Начиная с PHP 5.3 вы можете использовать статическое ключевое слово для вызова метода из вызываемого класса. то есть:

 <?php class A { public static function who() { echo __CLASS__; } public static function test() { static::who(); // Here comes Late Static Bindings } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); ?> 

Вышеприведенный пример выводит: B

источник: PHP.net / Поздние статические привязки

Я бы пошел с абстрактным классом ….
но в PHP вам не нужно использовать их, чтобы заставить его работать. Даже вызов конструктора родительского класса является «нормальным» вызовом метода, и объект на этом этапе полностью «работает», то есть $ this «знает» обо всех членах, унаследованных или нет.

 class Foo { public function __construct() { echo "Foo::__construct()\n"; $this->init(); } } class Bar extends Foo { public function __construct() { echo "Bar::__construct()\n"; parent::__construct(); } public function init() { echo "Bar::init()\n"; } } $b = new Bar; 

печать

 Bar::__construct() Foo::__construct() Bar::init() 

т.е. даже если класс Foo ничего не знает о функции init (), он может вызывать метод, поскольку поиск основан на том, что это за ссылка.
Это техническая сторона. Но вы действительно должны внедрить реализацию этого метода, либо сделав его абстрактным (принуждая потомков к его реализации), либо предоставив реализацию по умолчанию, которая может быть перезаписана.

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

Я создаю структуру MVC для приложения, у меня есть класс базового контроллера, который расширяется каждым отдельным классом контроллера. Каждый контроллер будет иметь разные методы, в зависимости от того, что должен делать контроллер. Например, mysite.com/event будет загружать контроллер событий. mysite.com/event/create загрузит контроллер событий и вызовет метод «create». Чтобы стандартизировать вызов функции create, нам нужен класс базового контроллера для доступа к методам дочернего класса, который будет отличаться для каждого контроллера. Таким образом, по коду, у нас есть родительский класс:

 class controller { protected $aRequestBits; public function __construct($urlSegments) { array_shift($urlSegments); $this->urlSegments = $urlSegments; } public function RunAction($child) { $FunctionToRun = $this->urlSegments[0]; if(method_exists($child,$FunctionToRun)) { $child->$FunctionToRun(); } } } 

Тогда класс child:

 class wordcontroller extends controller { public function add() { echo "Inside Add"; } public function edit() { echo "Inside Edit"; } public function delete() { echo "Inside Delete"; } } 

Таким образом, решение в моем случае состояло в том, чтобы передать дочерний экземпляр обратно родительскому классу в качестве параметра.

Единственный способ, которым вы могли бы это сделать, – это отражение . Однако отражение является дорогостоящим и его следует использовать только при необходимости.

Настоящая проблема заключается в том, что родительский класс никогда не должен полагаться на существование метода дочернего класса. Это руководящий принцип OOD и указывает на серьезный недостаток вашего дизайна.

Если ваш родительский класс зависит от определенного дочернего элемента, то он не может использоваться никакими другими дочерними классами, которые могут его расширить. Отношения между родителем и ребенком идут от абстракции к специфике, а не наоборот. Вам было бы намного лучше поместить требуемую функцию в родительский класс и переопределить ее в дочерних классах, если это необходимо. Что-то вроде этого:

 class whale { function myfunc() { echo "I am a ".get_class($this); } } class fish extends whale { function myfunc() { echo "I am always a fish."; } } 

что, если кит не будет расширен? что вызовет эта функция? К сожалению, нет никакого способа сделать это.

О, и рыбка протягивает кита? Рыба – это рыба, кит – млекопитающее.

Это очень просто. Вы можете сделать это без абстрактного класса.

 class whale { function __construct() { // some code here } /* Child overridden this function, so child function will get called by parent. I'm using this kind of techniques and working perfectly. */ function test(){ return ""; } function myfunc() { $this->test(); } } class fish extends whale { function __construct() { parent::construct(); } function test() { echo "So you managed to call me !!"; } } 

Даже если это старый вопрос, это мое решение с использованием ReflectionMethod:

 class whale { function __construct() { // some code here } function myfunc() { //Get the class name $name = get_called_class(); //Create a ReflectionMethod using the class and method name $reflection = new \ReflectionMethod($class, 'test'); //Call the method $reflection->invoke($this); } } 

Преимущество использования класса ReflectionMethod заключается в том, что вы можете передать массив аргументов и проверить, какой из них необходим в способе, который вы вызываете:

  //Pass a list of arguments as an associative array function myfunc($arguments){ //Get the class name $name = get_called_class(); //Create a ReflectionMethod using the class and method name $reflection = new \ReflectionMethod($class, 'test'); //Get a list of parameters $parameters = $reflection->getParameters() //Prepare argument list $list = array(); foreach($parameters as $param){ //Get the argument name $name = $param->getName(); if(!array_key_exists($name, $arguments) && !$param->isOptional()) throw new \BadMethodCallException(sprintf('Missing parameter %s in method %s::%s!', $name, $class, $method)); //Set parameter $list[$name] = $arguments[$name]; } //Call the method $reflection->invokeArgs($this, $list); }