2009-02-05 3 views
5

В практическом тесте был интересный вопрос, на который я не понял ответа. Какой выход из следующего кода:Вызов статического метода из класса B (который расширяет класс A) класса A

<?php 
class Foo { 
    public $name = 'Andrew'; 

    public function getName() { 
     echo $this->name; 
    } 
} 

class Bar extends Foo { 
    public $name = 'John'; 

    public function getName() { 
     Foo::getName(); 
    } 
} 

$a = new Bar; 
$a->getName(); 
?> 

Сначала я подумал, что это приводит к ошибке, так как статические методы не могут ссылаться на $ это (по крайней мере в PHP5). Я испытал это сам, и на самом деле он выводит Джона.

Я добавил Foo :: getName(); в конце скрипта и получил ошибку, которую я ожидал. Итак, что изменяется, когда вы вызываете статический метод из класса, который расширяет класс, из которого вы звоните?

Не мог бы кто-нибудь объяснить подробно, что здесь происходит?

ответ

2

$ это объект, в контексте которой был вызван метод. Итак: $ это $ a-> getName() - $ a. $ this в $ fooInstance-> getName() будет $ fooInstance. В случае, когда $ this задан (в вызове метода объекта $ a), и мы вызываем статический метод, $ this остается назначенным на $ a.

Похоже, из-за использования этой функции может возникнуть путаница. :)

4

Если вы вызываете статический метод, связанный с другим объектом, метод выполняется в контексте текущего объекта. Это позволяет получить доступ к $ this-объекту.

Лучший способ вызвать суперкласс-метод внутри подкласса будет:

parent::getName(); 
+0

Есть ли символ super :: в PHP? Единственный, о котором я могу думать, это parent :: для статических классов. –

+0

супер, похоже, не работает, родитель делает. – notruthless

+0

Вы правы, меня перепутали – Ulf

1

Когда вы вызываете $a->getName(), вы ссылаетесь на определенный объект, $a, который имеет класс Bar и поэтому возвращает «Джон».

Foo::getName() не действует вне функции, потому что нет конкретного объекта.

Я не уверен, что он работает на PHP, но если вы листинг объект для суперкласса, как в (Foo)$a->getName(), тогда вы получите «Андрей» в качестве своего результата. Вы все равно будете говорить об определенном объекте ($a), но в этом случае типа Foo. (Примечание Вы не обычно хотят, чтобы сделать это)

7

Foo :: GetName() использует старую PHP4 стиль scope resolution operator, чтобы позволить переопределяется метод будет называться.

В PHP5 вы будете использовать parent :: GetName() вместо

Это полезно, если вы хотите расширить, а не полностью переопределить поведение базового класса, например, это может стать яснее

class Bar extends Foo { 
    public $name = 'John'; 

    public function getName() { 
     echo "My name is "; 
     parent::getName(); 
    } 
} 
1

Иногда программисты лучше разбираются в коде, чем на английском!

Первое, что происходит здесь, - это концепция перегрузки. Когда вы создаете экземпляр Bar, метод getName() перегружает метод с тем же именем в Foo.

Перегрузка является важной и важной частью OOD.

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

Вот пример:

class Dog 
{ 
    public function getTag() 
    { 
     return "I'm a dog."; 
    } 
} 

class Skip extends dog 
{ 
    public function getTag() 
    { 
     return Dog::getTag() . " My name is Skip."; 
     // I'm using Dog:: because it matches your example. However, you should use parent:: instead. 
    } 
} 

$o = new Skip(); 
echo $o->getTag(); // Echo's: "I'm a dog. My name is Skip." 

Очевидно, что это очень приходской пример, но он иллюстрирует точку.

Ваш базовый класс является наиболее общей реализацией типа. В этом случае это «Собака». Вы хотите поместить информацию в этот базовый класс, который является общим для всех экземпляров этого типа. Это предотвращает дублирование в каждом из классов Derived (например, «Skip»).

Ваш скрипт использует эту функцию, возможно, непреднамеренно.

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