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 !!";
}


}
104655 次浏览

如果鲸鱼没有被扩展会怎样? 那个函数调用会导致什么结果? 不幸的是没有办法做到这一点。

哦,鱼能延伸鲸鱼吗? 鱼就是鱼,鲸鱼就是哺乳动物。

好吧,这个问题有很多错误,我不知道从哪里开始。

首先,鱼不是鲸鱼,鲸鱼也不是鱼。鲸鱼是哺乳动物。

其次,如果你想从父类中调用一个不存在的子类中的函数,那么你的抽象是有严重缺陷的,你应该从头开始重新考虑。

第三,在 PHP 中,你可以这样做:

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

whale的实例中它会导致一个错误。在 fish的实例中它应该工作。

唯一的方法就是通过 反思。然而,反射是昂贵的,只有在必要时才应该使用。

这里真正的问题是父类永远不应该依赖于子类方法的存在。这是面向对象设计的指导原则,表明您的设计存在严重缺陷。

如果父类依赖于特定的子类,则 任何其他的子类不能使用它,因为它也可以扩展它。亲子关系从抽象到具体,而不是反过来。您最好将所需的函数放在父类中,并在必要时在子类中重写它。就像这样:

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


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

从技术上讲,您不能从一个鲸鱼实例(父实例)调用一个 fish 实例(子实例) ,但是由于您正在处理继承,因此 myFunc ()无论如何都会在您的 fish 实例中可用,所以您可以直接调用 $yourFishInstance->myFunc()

如果您引用的是 模板方法,那么只需编写 $this->test()作为方法体。从 鱼的例子调用 myFunc()将把调用委托给 fish 实例中的 test()。但同样,不能从鲸鱼实例调用鱼类实例。

旁注: 鲸鱼是哺乳动物,不是鱼;)

这就是 抽象类的作用。一个抽象类基本上说: 无论谁从我继承,必须有这个函数(或这些函数)。

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();

我会选抽象课。
但是在 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()

也就是说,即使 福同学函数 init ()一无所知,它也可以调用该方法,因为查找是基于 $this 引用的。
这是技术层面的问题。但是您确实应该通过使其抽象(强制后代实现它)或提供可以被覆盖的默认实现来强制实现该方法。

我知道这对你来说可能有点晚了,但我也必须解决这个问题。为了帮助其他人理解为什么有时候这是一个必要条件,下面是我的例子:

我正在为一个应用程序构建一个 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";
}
}

因此,在我的例子中,解决方案是将子实例本身作为参数传递回父类。

从 PHP 5.3开始,您可以使用 static 关键字从调用的类中调用一个方法。例如:

<?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

来源: Net/后期静态绑定

好吧,这个答案是非常晚,但为什么没有人想到这一点?

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!

我使用这个函数来调用钩子方法,这些方法的 可以是由子类定义的,但不一定是。

这非常简单,不需要使用抽象类就可以完成。

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 !!";
}


}

即使这是一个老问题,这也是我使用 RefectionMethod 的解决方案:

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);
}
}

使用 RefectionMethod 类的好处是,您可以传递一个参数数组,并检查正在调用的方法中需要哪些参数:

    //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);
}

如果子类中存在方法,则将从父类调用方法(如果存在,则作为可选的回调)

<?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'));

鲸鱼实例你不能调用这个函数。但是从 实例你可以做

function myfunc()
{
static::test();
}

这有点棘手 如果你谈论 OOP 的概念,那是不可能的

但是如果你用你的大脑,那么它可以是:)

OOP 说的是,你不能从父类调用子类函数,这是正确的,因为继承是由继承子类中的父函数构成的

但是

你可以用静态类来实现这一点

class Parent
{
static function test()
{
HelperThread::$tempClass::useMe();
}
}


class child extends parent
{
// you need to call this. functon everytime you want to use
static function init()
{
HelperThread::$tempClass = self::class;
}


static function useMe()
{
echo "Ahh. thank God you manage a way to use me";
}


}


class HelperThread
{
public static  $tempClass;
}

这只是解决我问题的办法。 希望能帮到你

快乐编码:)