2012-02-24 3 views
2

Мне всегда казалось, что я понимаю, как работает ООП (и я использую его в течение многих лет), но иногда я понимаю, что некоторые понятия все еще не так ясны для меня.

Я только что наткнулся на this question о методе видимости в PHP. В accepted answer объясняется, что частный метод не может быть переопределен дочерним классом в PHP. Хорошо, это имеет смысл. Однако, этот пример заставлял меня думать о внутреннем механизме наследования в PHP, а способ $this ведет себя по унаследованным методам.

Рассмотрим этот код (example from the PHP Manual, также включены в вопрос упомянутой выше):

class Bar 
{ 
    public function test() { 
     $this->testPrivate(); 
     $this->testPublic(); 
    } 

    public function testPublic() { 
     echo "Bar::testPublic\n"; 
    } 

    private function testPrivate() { 
     echo "Bar::testPrivate\n"; 
    } 
} 

class Foo extends Bar 
{ 
    public function testPublic() { 
     echo "Foo::testPublic\n"; 
    } 

    private function testPrivate() { 
     echo "Foo::testPrivate\n"; 
    } 
} 

$myFoo = new foo(); 
$myFoo->test(); 

/* 
Output: 

Bar::testPrivate 
Foo::testPublic 
*/ 

Теперь рассмотрим этот excerpt from the PHP Manual:

Псевдо-переменная $ это доступна, когда метод вызывается из контекста объекта. $ это ссылка на вызывающий объект (обычно объект, к которому принадлежит этот метод, но, возможно, другой объект, если метод вызван статически из контекста вторичного объекта).

объяснение гласит, что «$this является ссылкой на вызывающий объект», который $myFoo. Поэтому я ожидал, что $myFoo->test() всегда будет ссылаться на Foo::testPrivate и никогда Bar::testPrivate (за исключением случаев, когда $myFoo был экземпляром Bar). Я проверил $this с get_class, и он всегда возвращает Foo, даже изнутри Bar::testPrivate и Bar::test. Однако $this ведет себя как экземпляр Bar, когда Bar::test звонит $this->testPrivate().

Это действительно сбивает с толку, и я пытаюсь понять , почему работает так!

Я думал, что унаследованные методы (или protected) были как-то скопированы с базы на дочерний класс. Частные методы не будут скопированы вообще. Но этот пример показывает, что он не работает так. Похоже, что экземпляр Foo хранит внутренний экземпляр Bar и делегирует ему вызовы методов, когда это необходимо.

Я пытаюсь узнать что-то здесь, и я только узнаю, когда для меня есть смысл. Этого нет. После того, как все это пишу, я думаю, что я могу суммировать его с двумя вопросами:

  1. Может кто-нибудь вкратце объяснить, как работает наследование внутренне в PHP? Или, по крайней мере, указать мне на статью или документацию?

  2. Является ли поведение или $this обсуждаемым здесь, присутствующим на других языках OO, или же оно относится к PHP?

ответ

4

Наследование в PHP работает так же, как на большинстве объектно-ориентированных языков.

Когда у вас есть «виртуальный» метод, метод не привязан непосредственно к вызывающему.Вместо этого каждый класс содержит небольшую таблицу поиска, в которой говорится, что «это имя метода связано с этой реализацией». Итак, когда вы говорите $this->testPublic(), что на самом деле происходит то, что PHP:

  • Возвращает виртуальную таблицу для текущего класса
  • Смотрит запись виртуальной таблицы для testPublic в этой таблице
  • Запускает метод, к которому что поиск точки

Поскольку Foo переопределяет testPublic, его виртуальная таблица содержит записи для testPublic указывающих на Foo::testPublic.

Теперь, с помощью частных методов, поведение отличается. Поскольку, как вы правильно читаете, частные методы не могут быть переопределены, вызов частного метода никогда не приводит к поиску виртуальной таблицы. То есть частные методы не могут быть виртуальными и должны всегда определяться в классе, который их использует.

Таким образом, эффект в том, что имя связывается в момент декларации: все Foo методы будут называть Foo::testPrivate, когда они говорят $this->testPrivate, и все Bar методы будут называть Bar::testPrivate.

Подводя итог, говоря, что «унаследованные методы копируются в дочерние» неверны. На самом деле происходит то, что дочерний элемент начинается с того, что его таблица имен методов-имен заполняется записями родительского класса, а затем добавляет свои собственные функции и заменяет любые переопределенные записи. Когда вы вызываете $this->something, эту таблицу поиска можно получить у для класса текущего объекта. Так, если $this является экземпляром Foo, а Foo переопределяет testPublic, вы получаете Foo::testPublic. Если $this является экземпляром Bar, вы получите Bar::testPublic.

+0

Спасибо, теперь это намного яснее. – bfavaretto

+0

+1 от оригинального ответчика. Я знал, КАК это работает, но не ПОЧЕМУ. Спасибо за информацию. – rockerest

1

Хорошо, private Методы и свойства - это то, что - частные. Для всех целей и целей вы можете считать их «внутренними», что означает внутреннее для класса, в котором они определены. Это означает, что они никогда не унаследованы и никогда не могут быть переопределены.

Таким образом, при использовании $this в сочетании с методом или свойством private, он всегда будет метод или свойство в пределах того же класса, что и применительно к $this. Это происходит потому, что $this, вызываемый в родительском классе, не может получить доступ к private методам или свойствам в другом классе (поскольку они являются частными), даже из дочерних классов.

Надеюсь, это поможет.

Смежные вопросы