请查看以下代码段:
<?php
class A {
function fn() {
print 'Context: Class:' . get_class($this)
. ' Parent:' . get_parent_class($this) . "\n";
if(get_parent_class($this)) {
parent::fn();
}
}
}
class B extends A { }
class C extends B { }
$a = new A();
$c = new C();
$a->fn();
print "\n";
$c->fn();
?>
通过运行它,您将获得以下输出:
Context: Class:A Parent:
Context: Class:C Parent:B
Fatal error: Cannot access parent:: when current class scope has no parent in /home/andrei/test/test.php on line 10
我认为它应该是这样的:
Context: Class:A Parent:
Context: Class:C Parent:B
Context: Class:B Parent:A
Context: Class:A Parent:
你怎么看?如果get_parent_class($this)
返回非假值,我们应该安全地假设parent ::已定义吗?在什么类上下文中调用fn()
?
答案 0 :(得分:3)
使用parent ::或self ::的调用被认为是静态的。这些应该在定义类的上下文中进行评估,而不是在调用对象的范围内进行评估。 PHP 5.3为单词 static 添加了一个新的含义,它可用于静态调用,如 parent和self,但将在调用类的上下文中进行评估即可。这称为延迟静态绑定。本页更多信息:
修改强>
经过一番思考后,我相信这种行为是完全可以接受的。首先,让我们看看为什么A希望它的foo()方法调用其父级的foo()方法,因为A没有父级。因为,无论子项的实现如何,它都希望始终执行该方法。如果是这样,还有其他解决方案,但不是很好:
class A
{
final public function __construct()
{
echo __METHOD__;
$this->foo();
$init = array($this, 'init');
$args = func_get_args();
call_user_func_array($init, $args);
}
// init would be used as a pseudo-constructor in children
public function init()
{}
final private function foo()
{
echo __METHOD__;
}
}
class B extends A
{}
class C extends B
{}
$c = new C;
如果您尝试做的是执行链中的每个foo()方法,那么它就是预期的行为。如果有一个B :: foo()函数那么就会被执行,如果它包含对parent :: foo()的调用,那么A :: foo()也会被执行。
所以,可能是父:: foo()在某种程度上令人困惑。它应该像(对不起,但我找不到更好的例子):
the_first_parent_in_the_inheritance_chain_which_has_a_foo_method :: foo的()
这就是你真正感兴趣的内容。为什么你想在B的上下文中调用foo()?我能想到的唯一原因是从B访问私人会员。但是,A怎么会知道私人会员B有什么?它不能。您不能在A尚未声明的A :: foo()成员中使用。除非A是抽象的并且定义了一些抽象方法。当然,A可以宣称该财产是私有的(B不能给被覆盖的成员提供比父母更低的可见度,我们的目标是B应该有私有财产)。 然后B覆盖该属性,使其成为我们想要的私有。现在,如果您的代码有效,A或C可以访问B的私有成员,尽管它不应该。这违反了规则。
是否有任何情况需要您提出的行为?
答案 1 :(得分:1)
我不是php向导,但我猜想问题是父母是静态的
答案 2 :(得分:1)
根据您的问题提示我自己的实验,似乎parent ::被解析为语句所在类的父级。如下所示更改您的测试用例以查看此行为:
<?php
class Z {
function fn() {
print "This is Z\n";
}
}
class A extends Z {
function fn() {
print 'Context: Class:' . get_class($this)
. ' Parent:' . get_parent_class($this) . "\n";
if(get_parent_class($this)) {
parent::fn();
}
}
}
class B extends A { }
class C extends B { }
$a = new A();
$c = new C();
$a->fn();
print "\n";
$c->fn();
?>
我同意这不直观,可能是一个错误。
更新: 有趣的是当你使用它来调用父代时会发生什么:
eval(get_parent_class($this). "::fn();");
答案 3 :(得分:1)
我认为你要做的事情是错的。如果你的类C定义了fn()函数,那么它永远不会在类A中调用fn(),所以这并不意味着说parent :: fn bcoz ur parent没有函数fn,这就是它回落到fn的原因()在A。中定义。
但是如果你想在当前对象上下文中调用其他函数使用$ this而不是parent 。 Herez代码。
<?php
class A {
function fn() {
print 'Context: Function:'.__FUNCTION__.' Class:' . get_class($this)
. ' Parent:' . get_parent_class($this) . "\n";
if(get_parent_class($this)) {
$this->fB();
}
}
}
class B extends A { }
class C extends B {
function fB(){
print 'Context: Function:'.__FUNCTION__.' Class:' . get_class($this)
. ' Parent:' . get_parent_class($this) . "\n";
}
}
$a = new A();
$c = new C();
$a->fn();
print "\n";
$c->fn();
?>
**out put**
Context: Function:fn Class:A Parent:
Context: Function:fn Class:C Parent:B
Context: Function:fB Class:C Parent:B
答案 4 :(得分:0)
你不能试着打电话给parent-&gt; fn() 我以前从未尝试过这样的东西,但那是我的第一次猜测......