在查看一些PHP代码时,我发现了一件奇怪的事情。以下是它的简单示例说明:
文件A.php:
<?php
class A{
public function methodA(){
echo $this->B;
}
}
?>
文件B.php:
<?php
class B extends A{
public $B = "It's working!";
}
?>
文件test.php:
<?php
require_once("A.php");
require_once("B.php");
$b = new B();
$b->methodA();
?>
运行test.php打印出“它正在工作!”,但问题是它为什么有效? :)这是一个功能还是一个bug?类A中的方法方法A也可以调用类B中的方法,这些方法不应该在OOP中工作。
答案 0 :(得分:12)
您只是实例化了课程B
。暂时忽略A
,并假装methodA()
是课程B
的一部分。
当课程B
延伸A
时,它会获得所有A
的功能。在代码运行之前,不评估$this->B
,而不是之前。因此,不会发生错误,并且在$this->B
类中存在B
时不会发生错误。
答案 1 :(得分:6)
PHP是一种动态语言。方法和数据成员在运行时进行评估。当您调用方法或访问成员时,PHP实际上会查找排序的哈希表,以确定是否可以在此对象上访问此方法或成员,这可以是继承层次结构中的任何位置。
不仅仅是继承,你总是可以在运行时将任意数据分配给一个对象,而且类中的代码仍然可以使用$ this-&gt;这样的东西来访问它,其中'某些东西'甚至不存在于课堂上
答案 2 :(得分:3)
$this
只是一个对象变量 - 一个特殊的变量,因为它是当前变量,但它仍然只是一个对象变量。
因为$B::B
是一个公共成员变量,所以可以从任何地方访问B
实例的引用,例如用对象变量。
随着公共成员随处可访问,任何功能,甚至可以从A::methodA()
内访问。
所以实际上并不奇怪。示例中的类继承仅涉及在调用$this
时以A::methodA()
“参数”的形式传递对象变量的(不可见)。
请参阅以下示例,该示例可能使其更加明显:
function methodA($object) {
echo $object->B;
}
class B {
public $B = "It's working!";
public function methodA() {
methodA($this);
}
}
答案 3 :(得分:2)
由于PHP是一种动态语言,因此调用正在使用它的实例上可能存在的属性或方法没有任何问题(在本例中是子类B的实例)
答案 4 :(得分:1)
PHP是一种动态语言。当在B的实例上调用methodA()时,B的成员$ B确实存在。
$a = new A();
$a->methodA();
无效。
在某些动态语言中,您甚至可以在运行时定义方法。
答案 5 :(得分:1)
这对我有意义;由于出现在B类中,因此$ B在结果对象中可用。因为$ this-&gt; B在运行时被计算,并且在此之前设置了值(当实例化B类时),它被发现设置正确。
您也可以使用方法执行此操作,因为它们的存在在执行之前不会被检查(尽管通常在方法的情况下在父类中声明它们是抽象的,因此强制子项实现它们)。
答案 6 :(得分:1)
这就是OOP的工作方式。起初看起来有点奇怪,因为您认为A必须首先知道$this->B
是什么(实际上在某些语言中这会产生编译器警告),但行为是正确的,因为子类你正在使用的是定义你的函数正在寻找的变量。如果您从methodA()
的实例调用A()
,则会出现“未定义”错误。
现在,奇怪的是(读:错误),如果 THIS 有效:
class A {
public $b = "Derp";
}
class B extends A {
function sayIt() { echo $this->b; }
}
$a = new A();
$a->sayIt();
答案 7 :(得分:0)
B类从A类扩展,因此它继承了A类中的方法methodA()
。