При работе с наследованием в 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();
Некоторые вопросы:
И это еще один пример:
<?phpclass 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>";
Быть собственностью $ а приват, я ожидать, что не сможет получить к нему доступ или сделать что-нибудь с ним из класса б.
Это немного бессмысленно для моего настоящего понимания.
Это ожидаемая функциональность, хотя B наследует все методы A, они не вызываются в контексте B, они вызываются в контексте A. Таким образом, вызывается конструктор A. Это означает, что функции, определенные в A, могут обращаться к свойствам A, даже когда объект расширен. Однако методы, определенные в A, не могут получить доступ к свойствам B, что, по-видимому, является вашим пониманием.
Итак, чтобы коротко ответить на ваши вопросы:
Объявление 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
учебный класс.
Объявление 2: Да, каждый объект, который является экземпляром подкласса, может использоваться вместо суперкласса. Вот почему вы должны писать свои классы, чтобы они могли быть заменены, когда статическая типизация требует суперкласса. Для получения дополнительной информации по этому вопросу см. Принцип подстановки Лискова.
Что касается последнего примера: снова нет кода в подклассе, который работал бы с частными членами суперкласса. Весь код работает в контексте суперкласса. Так что здесь нет проблем.
Если вы попытаетесь перегрузить методы суперкласса и использовать его закрытые члены, вот что:
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
}
}