如何从父类调用子类的函数? 考虑一下:
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 !!";
}
}
答案 0 :(得分:94)
这就是abstract classes的用途。一个抽象类基本上说:无论谁继承我,都必须具备这个功能(或这些功能)。
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();
答案 1 :(得分:27)
好的,这个答案很晚,但为什么没有人想到这个?
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!
我用它来调用钩子方法,可以由子类定义,但不一定是。
答案 2 :(得分:15)
从技术上讲,你不能从鲸实例(父)中调用fish实例(子),但由于你正在处理继承,myFunc()无论如何都会在你的fish实例中可用,所以你可以调用{{1}直接。
如果您正在引用template method pattern,那么只需将$yourFishInstance->myFunc()
写为方法正文。从 fish实例调用$this->test()
会将调用委托给fish实例中的myFunc()
。但同样,没有从鲸鱼实例到鱼类实例的调用。
在旁注中,鲸鱼是哺乳动物而不是鱼;)
答案 3 :(得分:9)
好吧,这个问题有很多问题,我真的不知道从哪里开始。
首先,鱼不是鲸鱼,鲸鱼不是鱼。鲸鱼是哺乳动物。
其次,如果你想从父类中不存在的父类调用子类中的函数,那么你的抽象存在严重缺陷,你应该从头开始重新思考它。
第三,在PHP中你可以做到:
function myfunc() {
$this->test();
}
在whale
的实例中,它会导致错误。在fish
的实例中,它应该有用。
答案 4 :(得分:6)
从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();
?>
以上示例将输出: 乙
答案 5 :(得分:3)
我会选择抽象类.... 但是在PHP中你不必使用它们来使它工作。甚至调用父类的构造函数也是一个“正常”的方法调用,此时对象完全“可操作”,即$“知道”所有成员,是否继承。
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()
即。即使 class Foo 对函数init()一无所知,它也可以调用该方法,因为查找是基于$ this引用的。 /> 这是技术方面。但是你真的应该通过使它成为抽象(强制后代实现它)或提供可以覆盖的默认实现来强制执行该方法。
答案 6 :(得分:2)
我知道这对你来说可能有点晚了,但我也不得不解决这个问题。为了帮助其他人理解为什么这有时是一个要求,这是我的例子:
我正在为应用程序构建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";
}
}
因此我的解决方案是将子实例本身作为参数传递回父类。
答案 7 :(得分:1)
你能做到这一点的唯一方法是通过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.";
}
}
答案 8 :(得分:1)
即使这是一个老问题,这是我使用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);
}
答案 9 :(得分:0)
这很简单。你可以在没有抽象类的情况下做到这一点。
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 !!";
}
}
答案 10 :(得分:0)
如果子类中存在方法,则将从父类中调用该方法(如果存在则作为可选回调)
<?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'));
答案 11 :(得分:0)
在 鲸鱼 实例中,您无法调用此函数。但您可以从 鱼 实例
function myfunc()
{
static::test();
}
答案 12 :(得分:-1)
如果鲸鱼没有延长怎么办?该函数调用会产生什么结果?不幸的是没有办法做到这一点。
哦,鱼是否延长了鲸鱼?鱼是鱼,鲸鱼是哺乳动物。