При просмотре кода PHP я обнаружил странную вещь. Вот его пример:
Файл A.php:
<?php class A{ public function methodA(){ echo $this->B; } } ?>
Файл B.php:
<?php class B extends A{ public $B = "It's working!"; } ?>
Файл test.php:
<?php require_once("A.php"); require_once("B.php"); $b = new B(); $b->methodA(); ?>
Запуск test.php выводит «Работает!», Но вопрос в том, почему он работает? 🙂 Является ли это признаком или ошибкой? Метод methodA в классе A также может вызывать методы, которые находятся в классе B, которые не должны работать в ООП.
Вы создаете экземпляр класса B
Игнорируйте A
на данный момент и притворитесь, что methodA()
является частью класса B
Когда класс B
расширяет A
, он получает все функции A
$this->B
не оценивается до тех пор, пока код не будет запущен, а не ранее. Поэтому ошибка не возникает и не будет возникать, поскольку $this->B
существует в классе B
PHP – динамический язык. Методы и элементы данных оцениваются во время выполнения. Когда вы вызываете метод или получаете доступ к члену, PHP на самом деле ищет хэш-таблицу, чтобы выяснить, доступен ли этот метод или член на этом объекте или нет, что может быть где угодно в иерархии наследования.
И не только наследование, вы всегда можете назначить произвольные данные объекту во время выполнения, а код внутри класса по-прежнему сможет получить к нему доступ, используя $ this-> нечто, где «что-то» даже не существует в классе.
$this
просто объектная переменная – специальная, потому что она является текущей, но она по-прежнему является только переменной объекта.
Поскольку $B::B
– это переменная открытого члена, к ней можно получить доступ из любой точки, где ссылка на экземпляр B
может достижима, например, с переменной объекта.
Поскольку публичные члены доступны повсюду, любая функция, даже изнутри A::methodA()
может быть доступна.
Так что на самом деле не о чем беспокоиться. Наследование класса в вашем примере относится только к (невидимой) передаче объектной переменной в форме $this
«parameter» при A::methodA()
.
См. Следующий пример, который, вероятно, делает его более заметным:
function methodA($object) { echo $object->B; } class B { public $B = "It's working!"; public function methodA() { methodA($this); } }
Поскольку PHP является динамическим языком, нет ничего неправильного в вызове свойств или методов, которые могут существовать в экземпляре, который его использует (в данном случае экземпляре подкласса B)
PHP – динамический язык. Когда методA () вызывается в экземпляре B, член B B фактически существует.
$a = new A(); $a->methodA();
не будет работать.
В некоторых динамических языках вы даже можете определять методы во время выполнения.
Это имеет смысл для меня; $ B становится доступным в результирующем объекте в силу его появления в классе B. Поскольку $ this-> B оценивается во время выполнения, и значение устанавливается перед этим (когда экземпляр класса B создается), оказывается, что правильно установить.
Вы можете сделать это также с помощью методов, поскольку их существование не проверяется до тех пор, пока они не будут выполнены (хотя обычно в случае методов объявлять их абстрактными в родительском классе, тем самым вынуждая ребенка реализовать их).
Вот как должен работать ООП. Сначала это может показаться немного странным, так как вы думаете, что A должен знать, что такое $this->B
в первую очередь (и действительно, на некоторых языках это приведет к предупреждению компилятора), но поведение правильное, поскольку подкласс вы используете определение переменной, которую ищет ваша функция. Если вы вызвали methodA()
из экземпляра A()
, вы получите сообщение об ошибке «undefined».
Теперь, что было бы странно (читай: неправильно ), если ЭТО работает:
class A { public $b = "Derp"; } class B extends A { function sayIt() { echo $this->b; } } $a = new A(); $a->sayIt();
Класс B распространяется от класса A, поэтому он наследует метод метода methodA()
из класса A.