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 !!";
}
}
Ответы
Ответ 1
То, что для абстрактных классов. Абстрактный класс в основном говорит: "Кто наследует меня, должен иметь эту функцию (или эти функции).
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();
Ответ 2
Хорошо, этот ответ ОЧЕНЬ поздний, но почему никто не подумал об этом?
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, которые могут быть определены дочерним классом, но не обязательно.
Ответ 3
Технически вы не можете вызывать экземпляр рыбы (ребенка) из экземпляра кита (родителя), но поскольку вы имеете дело с наследованием, myFunc() будет доступен в вашем экземпляре рыбы в любом случае, поэтому вы можете напрямую вызвать $yourFishInstance->myFunc()
.
Если вы ссылаетесь на шаблон шаблона , просто напишите $this->test()
как тело метода. Вызов myFunc()
из экземпляра рыбы делегирует вызов test()
в экземпляре рыбы. Но опять же, нет вызова от экземпляра кита к экземпляру рыбы.
На сиднейте, кит - это млекопитающее, а не рыба;)
Ответ 4
Хорошо, в этом вопросе так много чего не так. Я не знаю, с чего начать.
Во-первых, рыба - это не киты, а киты - не рыба. Киты - это млекопитающие.
Во-вторых, если вы хотите вызвать функцию в дочернем классе из родительского класса, который не существует в вашем родительском классе, ваша абстракция серьезно испорчена, и вы должны пересмотреть ее с нуля.
В-третьих, в PHP вы можете просто сделать:
function myfunc() {
$this->test();
}
В случае whale
это приведет к ошибке. В случае fish
он должен работать.
Ответ 5
С 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();
?>
Вышеприведенный пример выводит:
В
source: PHP.net/Поздние статические привязки
Ответ 6
Я бы пошел с абстрактным классом....
но в 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(), он может вызывать метод, так как поиск основан на том, что означает $this.
Это техническая сторона. Но вы действительно должны внедрить реализацию этого метода, либо сделав его абстрактным (принуждая потомков к его реализации), либо предоставив реализацию по умолчанию, которая может быть перезаписана.
Ответ 7
Я знаю, что это, вероятно, немного поздно для вас, но мне также пришлось обойти эту проблему. Чтобы помочь другим понять, почему это иногда является требованием, вот мой пример:
Я создаю среду 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();
}
}
}
Тогда дочерний класс:
class wordcontroller extends controller {
public function add() {
echo "Inside Add";
}
public function edit() {
echo "Inside Edit";
}
public function delete() {
echo "Inside Delete";
}
}
Таким образом, решение в моем случае состояло в том, чтобы передать дочерний экземпляр обратно в родительский класс в качестве параметра.
Ответ 8
Единственный способ сделать это - через reflection. Однако отражение является дорогостоящим и должно использоваться только при необходимости.
Настоящая проблема заключается в том, что родительский класс никогда не должен полагаться на существование метода дочернего класса. Это руководящий принцип OOD и указывает, что в вашем дизайне есть серьезный недостаток.
Если ваш родительский класс зависит от определенного дочернего элемента, то он не может использоваться никакими другими дочерними классами, которые могут его расширить. Отношения между родителем и ребенком идут от абстракции к специфике, а не наоборот. Вам было бы намного лучше поместить требуемую функцию в родительский класс и переопределить ее в дочерних классах, если это необходимо. Что-то вроде этого:
class whale
{
function myfunc()
{
echo "I am a ".get_class($this);
}
}
class fish extends whale
{
function myfunc()
{
echo "I am always a fish.";
}
}
Ответ 9
Даже если это старый вопрос, это мое решение, используя 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);
}
Ответ 10
Это очень просто. Вы можете сделать это без абстрактного класса.
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 !!";
}
}
Ответ 11
Если существует метод в дочернем классе, метод будет вызван из родительского класса (в качестве необязательного обратного вызова, если существует)
<?php
class controller
{
public function saveChanges($data)
{
//save changes code
// Insert, update ... after ... check if exists callback
if (method_exists($this, 'saveChangesCallback')) {
$arguments = array('data' => $data);
call_user_func_array(array($this, 'saveChangesCallback'), $arguments);
}
}
}
class mycontroller extends controller
{
public function setData($data)
{
// Call parent::saveChanges
$this->saveChanges($data);
}
public function saveChangesCallback($data)
{
//after parent::saveChanges call, this function will be called if exists on this child
// This will show data and all methods called by chronological order:
var_dump($data);
echo "<br><br><b>Steps:</b><pre>";
print_r(array_reverse(debug_backtrace()));
echo "</pre>";
}
}
$mycontroller = new mycontroller();
$mycontroller->setData(array('code' => 1, 'description' => 'Example'));
Ответ 12
что, если кит не будет расширен? что вызовет эта функция? К сожалению, нет способа сделать это.
О, и рыбка удлиняет кита? Рыба - это рыба, кит - млекопитающее.