ООП в PHP(часть 2)

Бывает, что нужно инициализировать объект - присвоить его свойствам значения, которые были изначально. Предположим, имя класса Man и он содержит два свойства:имя человека и его фамилию. Можно написать метод, который будет выполнять инициализацию объекта, например Init():

<?php
// Создаем новый класс Man:
class Man {
// свойства:
var $name;
var $surname;
 
// Инициализирующий метод:
 function Init($name) {
 $this->name = $name;
 $this->surname = "Ivanov";
 }
}
// Создаем объект класса Man:
$object = new Man;
// Для инициализации объекта сразу вызываем метод:
$object->Init();
?>

Нужно вызвать функцию сразу после создания объекта, либо вызвать какой-нибудь метод между созданием объекта и его инициализацией, для того, чтобы PHP знал, что определенный метод нужно вызывать автоматически при создании объекта, ему нужно дать имя такое же, как и у класса:
function Man ($name)
$this->name = $name;
$this->surname = "Ivanov";
}

Обращение к элементам класса
Обращение к элементам классов осуществляется с помощью оператора ::. Используя "двойное двоеточие", можно обращаться к методам класса.
Пример:
<?php
class A {
     function example() {
         echo "Это первоначальная функция A::example().<br>";
     }
}
 
class B extends A {
     function example() {
         echo "Это переопределенная функция B::example().<br>";
         A::example();
     }
}
 
// Не нужно создавать объект класса A.
// Выводит следующее: 
// Это первоначальная функция A::example().
A::example();
 
// Создаем объект класса B.
$b = new B;
 
// Выводит следующее: 
//   Это переопределенная функция B::example().
//   Это первоначальная функция A::example().
$b->example();
?>

Наследование в PHP.
Наследование - это хорошо зарекомендовавший себя принцип программирования. PHP использует этот принцип в своей объектной модели. Этот принцип будет распространяться на то, каким образом множество классов и объектов относятся друг к другу.
Например, когда вы расширяете класс, дочерний класс наследует все публичные и защищенные методы из родительского класса. До тех пор пока не будут эти методы переопределены, они будут сохранять свою исходную функциональность.
Итак, пусть у нас есть некоторый класс First с определенными свойствами и методами. Но не все, что класс выполняет, нас устраивает — например, пусть он выполняет большинство функций, по сути нам необходимых, но не реализует некоторых других. Создадим новый класс Second, добавляющий функционал классу First. Сделать это можно двумя различными способами. Первый вариант:
<?php
class First {
  function TestFirst() { ... }
  function Test() { ... }
}
 
class Second {
  var $f; // объект класса First
  function Second(параметры_для_First, другие_параметры){ 
    $f = new First(параметры_для_First);
    // инициализируем другие поля Second
  }
  function TestSecond() { ... }
  function Test() { ... }
}
?>

Что произошло? В этой реализации объект класса Second содержит в своем составе объект класса First, как свойство. Это свойство — лишь часть объекта класса Second, не более того. Объект в First не "знает", что он в действительности не самостоятелен, а на самом деле содержится в классе Second, поэтому нельзя выполнять действия, специфичные для этого класса.
Итак, мы имеем получили некоторые проблемы:
1. Мы не видим явно, что класс Second лишь расширяет возможности First, а не является отдельной сущностью;
2. Мы должны обращаться к "части First" класса Second через $obj->f->TestFirst(), а к членам самого класса Second как $obj->TestSecond().
Теперь на практике рассмотрим, что такое наследование классов:
<?php
class Second extends First {
  function Second(параметры_для_First, другие_параметры) { 
    $this->First(параметры_для_First);
    // инициализируем другие поля Second
  }
 
  function TestSecond() { ... }
  function Test() { ... }
}
?>

Ключевое слово extends показывает, что создаваемый класс Second является лишь "расширением" класса First и проблемы, с которыми мы столкнулись выше в данном случае отпадают.
Введем немного определений: родительский класс First называют базовым классом, а класс дочерний класс Secondпроизводным от First. Иногда базовый класс также называют суперклассом, а производный — подкласcом.
Еще один пример:
<?php
class Parent {
  function parent_funct() { echo "<h1>Родительская функция</h1>"; }
  function test () { echo "<h1>Родительский класс</h1>"; }
}
 
class Child extends Parent {
  function child_funct() { echo "<h2>Дочерняя функция</h2>"; }
  function test () { echo "<h2>Дочерний класс</h2>"; }
}
 
$obj = new Parent;
$obj = new Child;
 
$obj->parent_funct(); // Вывод Родительской функции
$obj->child_funct(); // Вывод Дочерней
$obj->test(); // Выводит 'Дочерний класс'
?>

Дочерний класс Child наследует все методы и свойства суперкласса Parent.
Полиморфизм (многоформенность) следствие из идеи наследования. Вкратце, полиморфность класса — это свойство базового класса использовать функции производных классов, даже если на момент определения еще неизвестно, какой именно класс будет включать его в качестве базового и, тем самым, становиться от него производным.
Рассмотрим свойство полиморфности классов на примере:
<?php
class F {
// Выводит, функция какого класса была вызвана
function Test() { echo "Test from F\n"; }
// Тестовая функция — просто переадресует на Test()
function Call() { Test(); }
}
class S extends F {
// Функция Test() для класса S
function Test() { echo "Test from S\n"; }
}
$f=new F();
$s=new S();
?>

Используем команды:
$f->Call(); // выводит "Test from F"
$s->Test(); // выводит "Test from S"
$s->Call(); // Выводит "Test from S"!
!
Стоит внимательнее посмотреть на последнюю строчку: вопреки ожиданиям, вызывается не функция Test() из класса F, а функция из класса S! Складывается впечатление, что Test() из S просто переопределила функцию Test() из F. Так и есть. Функция, переопределяемая в производном классе, называется виртуальной.