2014-10-15 2 views
0

Имея дело с наследованием в PHP, я обнаружил некоторую нехватку знаний, в основном около конструкторы и частные объектов недвижимости.Конструктор может получить доступ к родительским частным свойствам в 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(); 

Некоторые вопросы:

  1. не должен B строительства вызвать конструктор в контексте B? (и поэтому я бы ожидал, что он не сработает, потому что он не унаследовал частную собственность $ module)
    • или PHP просто вызовет конструктор A, используя/ссылочные методы и свойства из A? (В том числе частных них)
  2. я могу перейти к $ б либо модуль или BModule объекта; это потому, что BModule является ребенком Модуль. Проверяет ли PHP некоторую цепочку наследования (проверяя родителей) прошедшего объекта при проверке типа намека?
    • так я могу передать конструктору либо объект типа модуля или BModule или CModule?

И это еще один пример:

<?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>"; 

Будучи собственностью $ в частные, я бы ожидать, чтобы не быть в состоянии получить доступ к этому или сделать что-нибудь с ним из класс b. Это немного не имеет смысла для моего реального понимания.

ответ

1

Ожидаемая функциональность, хотя B наследует все методы A, они не вызывают в контексте B, они вызывается в контексте A. Таким образом вызывается конструктор A. Это означает, что функции, определенные в A, могут получить доступ к свойствам A, даже если объект расширен. Однако методы, определенные в A, не могут получить доступ к свойствам B, что, по-видимому, является вашим пониманием.

Так коротко ответить на ваши вопросы:

  1. Нет, функции всегда вызываются в контексте того, где они определены, а не от того, где они называются.
  2. PHP проверяет всю цепочку наследования, чтобы убедиться, что это правильно. Можно предположить, что любой ребенок класса может иметь одинаковые функции.Поэтому, если B расширяет A, вы можете использовать либо B, либо A в качестве параметра, когда он тип-намекнул на A, но использовать только B, если его тип-намекнуть на B
+0

Я немного смущен. Поэтому, если у меня есть что-то простое, например 'class a {getClass() {return get_class ($ this);}}' и 'class b расширяет {}', а затем вызывает 'getClass()' в экземпляре ** b * * не вернется ** a **? (поскольку, как мы сказали, метод наследуется и выполняется в контексте родителя ** a **). Извините за плохое форматирование кода и извините за возможные глупые вопросы. – Kamafeather

+1

Правильно, это вернет B, а не A. Это потому, что _function_ вызывается в контексте A, но фактический _объект_, который $ this относится к прежнему типу B – Nathan

1

Объявление 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: Да, каждый объект, являющийся экземпляром подкласса, может использоваться вместо суперкласса. Вот почему вы должны писать свои классы, чтобы их можно было заменить, когда для статического ввода требуется суперкласс. Для получения дополнительной информации по этому вопросу см. 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 
    } 
} 
Смежные вопросы