在处理PHP中的继承时,我发现一些知识缺乏,主要是关于构造函数和私有属性。
让我们以此代码为例:
<?php
class Module
{
public $type;
public function __construct($type)
{
$this->type = $type;
}
}
class BModule extends Module
{
}
class CModule extends BModule
{
}
class A
{
private $module;
public function __construct(Module $module)
{
echo 'Set module for '.__CLASS__.' to '.$module->type . PHP_EOL;
echo "<br>";
$this->module = $module;
}
public function getModule()
{
echo "I (as " . __CLASS__ . ") have a module of type " . $this->module->type;
return $this->module->type;
}
}
class B extends A
{
}
$m = new Module('base-module');
$bm = new BModule('bi-module');
echo "<br>--------A---------<br>";
$a = new A($m);
echo "<br>A is of type " . $a->getModule();
echo "<br>--------B---------<br>";
$b = new B($bm);
echo "<br>B is of type " . $b->getModule();
有些问题:
这是另一个例子:
<?php
class a
{
private $a;
protected $a_copy;
public function __construct($a_value)
{
$this->a = $a_value;
$this->a_copy = $this->a;
}
public function getA()
{
return $this->a;
}
public function getCopyA()
{
return $this->a;
}
}
class b extends a
{
}
$a = new a('value for a');
$b = new b('value for b');
echo "<br>-----A-----<br>";
echo $a->getA()."<br>";
echo $a->getCopyA()."<br>";
echo "<br>-----B-----<br>";
echo $b->getA()." (I would expect to have no access to \$a)<br>";
echo $b->getCopyA()."<br>";
作为属性 $ a 私有,我希望无法访问或从 b 类中执行任何操作。 对于我的实际理解,这有点无意义。
答案 0 :(得分:1)
这是预期的功能,虽然B继承了A的所有方法,但它们不是在B的上下文中调用的,它们是在A的上下文中调用的。因此调用A构造函数。这意味着即使扩展了对象,A中定义的函数也可以访问A的属性。但是,A中定义的方法无法访问B的属性,这似乎是您的理解。
所以很快回答你的问题:
答案 1 :(得分:1)
Ad 1:不,被调用方法的上下文是声明方法(在本例中为构造函数)的地方。如果上下文是类B
,那么任何人都可以通过扩展它来破坏你的类。
看一下这个例子:
class A
{
private $module;
public function __construct(Module $module)
{
echo 'Set module for '.__CLASS__.' to '.$module->type . PHP_EOL;
echo "<br>";
$this->module = $module;
}
}
class B extends A
{
public function __construct()
{
parent::__construct(new Module()); // call the parent (which is A)
}
}
这说明了A::__construct()
的范围实际上是A
类。
Ad 2:是的,可以使用作为子类实例的每个对象来代替超类。这就是为什么你应该编写你的类,以便在静态类型需要超类时可以替换它们。有关此主题的更多信息,请参阅Liskov substitution principle。
至于最后一个例子:子类中没有代码可以对超类的私有成员进行操作。所有代码都在超类上下文中运行。所以这里没有问题。
如果您尝试重载超类的方法并使用其私有成员,则会出现问题:
class b extends a
{
public function getA()
{
return $this->a . "_suffix"; // error
}
}
在这种情况下,您必须依赖于超类中getA()
方法的实现:
class b extends a
{
public function getA()
{
return parent::getA() . "_suffix"; // ok, we are depending on the super class implementation
}
}