Язык РНР5 является объектно-ориентированным языком программирования. Объектно-ориентированное программирование (ООП) предлагает особый синтаксис и подходы к разработке и анализу программ. Основными элементами программ в ООП являются объекты. PHP до недавнего времени обеспечивал лишь некоторую поддержку ООП. Однако, после выхода PHP5 поддержка ООП в PHP стала практически полной.
Объектно-ориентированное программирование основано на:
Инкапсуляцией называется включение различных мелких элементов в более крупный объект, в результате чего программист работает непосредственно с этим объектом. Это приводит к упрощению программы, поскольку из нее исключаются второстепенные детали.
Полиморфизм позволяет использовать одни и те же имена для похожих, но технически разных задач. Главным в полиморфизме является то, что он позволяет манипулировать объектами путем создания стандартных интерфейсов для схожих действий. Полиморфизм значительно облегчает написание сложных программ.
Наследование позволяет одному объекту приобретать свойства другого объекта, не путайте с копированием объектов. При копировании создается точная копия объекта, а при наследовании точная копия дополняется уникальными свойствами, которые характерны только для производного объекта.
Класс — это описание, своего рода шаблон, по которому создаются объекты. Его можно рассматривать как своего рода "контейнер" для логически связанных данных и функций (обычно называемых методами). Если сказать проще, то класс - это своеобразный тип данных.
Объект — экземпляр класса. Это совокупность данных (свойств) и функций (методов) для их обработки. Свойства и методы называются членами класса. Вообще, объектом является все то, что поддерживает инкапсуляцию.
Если класс можно рассматривать как тип данных, то объект — как переменную (по аналогии). Скрипт может одновременно работать с несколькими объектами одного класса, как с несколькими переменными.
Внутри объекта данные и код (члены класса) могут быть либо открыты, либо нет. Открытые данные и члены класса являются доступными для других частей программы, которые не являются частью объекта. А вот закрытые данные и члены класса доступны только внутри этого объекта.
Описание классов в PHP начинаются служебным словом class и имеет следующий синтаксис:
class имя_класса {
определение_свойств
определение_методов
}
Объект создается на основе определенного класса с помощью оператора new:
$ имя_переменной = new имя_класса(параметры);
Свойства в определении класса задаются как обычные переменные. При этом вы можете использовать оператор присваивания, чтобы установить для свойств значение по умолчанию. Значения должны быть простыми(различных типов), а не задаваться посредством вычисляемых выражений. Для объявления переменных рекомендуется использовать ключевое слово var.
Пример создания класса:
<?php
// Создаем новый класс Coor:
class Coor {
// данные (свойства):
var $name;
var $addr;
// методы:
function Name() {
echo "<h3> Петр</h3>";
}
}
// Создаем объект класса Coor:
$object = new Coor;
//выводим объект
$object ->Name();
?>
В окне веб-браузера это будет выглядеть ТАК.
Внимание! Спецификатор (ключевое слово) var перед именем свойства означает доступность этого свойства из-за пределов кода класса. Вместо var можно использовать спецификатор public (публичный, общедоступный). Допустимы также и другие спецификаторы: private и protected, но они задают ограничения доступа к свойствам. При объявлении свойств указание спецификатора обязательно.
Мы рассмотрели, каким образом описываются классы и создаются объекты. Доступ к членам класса, обеспечивает оператор ->.
Методы объекта также являются его свойствами, но задаются не как переменные, а как функции. Методы обычно используются, чтобы изменить значение свойств объекта или произвести какие-нибудь другие действия. Если в методе(функции) требуется обратиться к какому-нибудь свойству(переменной) этого же объекта, то перед именем этого свойства следует указать префикс $this->. Метод задается в определении класса как обычная функция с использованием ключевого слова function.
Рассмотрим пример описывающий простой класс для создания счета.
<?php
class cheg {
var $summa=0; //остаток на счете
function wedsum($sum) { //добавление к сумме на счете
$sum=100;
$this->summa=$this->summa+$sum;
echo "Добавлено $sum рублей";
}
}
$object = new cheg;
$object->wedsum($sum);
?>
В окне веб-браузера это будет выглядеть ТАК.
Данный класс имеет одно свойство $summa и один метод wedsum(). Класс предназначен для хранения некоторого числа, понимаемого как остаток денежной суммы на некотором счете, т.е. как состояние счета. С помощью метода wedsum() можно изменить текущее состояние счета, указав в качестве параметра число, которое следует добавить к остатку счета(если это число положительное) или вычесть из остатка(если число отрицательное).
Рассмотрим еще один пример:
<?php
// Создаем новый класс Coor:
class Coor {
// данные (свойства):
var $name="Трофим";
// методы:
function Getname() {
echo $this->name;
}
function Setname($name) {
$this->name = $name;
}
}
// Создаем объект класса Coor:
$object = new Coor;
// Теперь для изменения имени используем метод Setname():
$object->Setname("Петр");
// А для доступа, как и прежде, Getname():
$object->Getname();
// Сценарий выводит 'Петр'
?>
В окне веб-браузера это будет выглядеть ТАК.
Для изменения имени ипользовался метод Setname(). Указатель $this можно также использовать для доступа к методам, а не только для доступа к данным:
function Setname($name) {
$this->name = $name;
$this->Getname();
}
Помимо методов, создаваемых разработчиками класса, объектно-ориентированная модель РНР предоставляет разработчику специальные методы. Специальные методы позволяют задать неявные свойства поведения объектов и выполняются как правило автоматически.
Примечание. Каждый специальный метод предваряется двумя символами подчеркивания.
Специальные методы классов
Метод | Описание |
__construct() | Конструктор класса; метод, который автоматически выполняется в момент создания объекта до вызова всех остальных мктодов класса |
__destruct() | Деструктор класса; метод, который автоматически выполняется в момент уничтожения объекта |
__autoload() | Перегружаемая функция, не являющаяся методом класса; позволяет автоматически создать класс при попытке создания объекта |
__set() | Аксессор; метод предназначенный для установки значения свойству |
__get() | Аксессор; метод предназначенный для чтения свойств |
__isset() | Позволяет задать логику проверки существования свойства при помощи конструкции isset() |
__unset() | Позволяет задать логику удаления свойства при помощи конструкции unset() |
__call() | Позволяет задать динамический метод |
__toString() | Позволяет интерполировать (подставлять) объект в строку |
__set_state() | Позволяет осуществлять экспорт объекта |
__clone() | Позволяет управлять клонированием объекта |
__sleep | Позволяет управлять поведением объекта при его сериализации при помощи функции serialize() |
__wakeup() | Позволяет управлять поведением объекта при его восстановлении из сериализованного состояния при помощи функции unserialize() |
Помимо методов входящих в состав классов, РНР предоставляет большое количество внешних функций, облегчающих работу с классами и объектами.
Список функций для работы с классами и объектами
Функция | Описание |
calla_user_method_array ($method_name, $obj [, $par]) |
Осуществляет вызов метода $method_name объекта $obj с массивом параметров $par. Функция признана устаревшей и будет исключена из последующих версий РНР; вместо нее рекомендуется использовать функцию call_user_func_array() |
call_user_func_array ($methor_name, $par) |
Осуществляет вызов метода или функции $methor_name с массивом параметров $par |
cfll_user_method ($method_name, $obj [, $par [, $par1, . . .]]) |
Осуществляет вызов метода $method_name объекта $obj с параметрами $par, $par1 и т.д. Функция признана устаревшей и будет исключена из последующих версий РНР; вместо нее рекомендуется использовать функцию call_user_func() |
call_user_func ($method_name [, $par [, $par1, . . .]]) |
Осуществляет вызов метода или функции $methor_name с параметрами $par, $par1 и т.д. |
class_exists($class_name) |
Возвращает true, если класс с именем $class_name объявлен, и false — в противном случае |
get_class_medhods ($class_name) |
Возвращает массив с именами методов класса $class_name |
get_class_vars ($class_name) |
Возвращает массив с именами и значения членов класса $class_name |
get_class($obj) | Возвращает имя класса, которому принадлежит объект $obj |
get_declared_classes() | Возвращает массив с именами объявленных классов |
get_declared_interfaces() | Возвращает массив с именами объявленных интерфейсов |
get_object_vars($obj) | Возвращает массив с именами и значениями членов объекта $obj |
get_parent_class($obj) | Возвращает имя базового класса для объекта или класса $obj |
interface_exists ($interface_name [, $autoload]) |
Возвращает true, если интерфейс с именем $interface_name существует, и false — в противном случае. Если необязательный параметр $autoload равен true, функция пытается загрузить интерфейс при помощи функции __autoload() |
is_a($obj, $class_name) |
Принимает в качестве первого параметра объект $obj, а в качестве второго — имя базового класса $class_name и возвращает true, если объект является экземпляром класса $class_name или экземпляром его потомка, и false — в противном случае |
is_callable($arr [, $syntax_only [, $callable_name]]) |
Определяет, может ли быть вызван метод класса |
is_object($obj) | Возвращает true, если пременная $obj является объектом, и false — в противном случае |
is_subclass_of($obj, $class_name) |
Принимает в качестве первого параметра объект $obj, а в качестве второго — имя базового класса $class_name и возвращает true, если объект является экземпляром потомка класса $class_name, и false — в противном случае |
method_exists($obj, $method_name) |
Возвращае true, если объект $obj обладает методом $method_name, и false — в противном случае |
print_r($obj [, $return]) |
Возвращает дамп объекта $obj. Если переменная $return принимает значение true, функция возвращает результат в виде строки, в противном случае результат выводится непосредственно в окно браузера |
property_exists ($class_name, $var) |
Возвращает true, если переменная $var является членом класса $class_name, и false — в противном случае |
Довольно часто при создании объекта требуется задать значения некоторых атрибутов. К счастью, разработчики технологии ООП учли это обстоятельство и реализовали его в концепции конструкторов. Конструктор выполняется при создании объекта на основе данного класса, хотя объект можно создать и не определяя конструктор явно. Обычно конструктор определяют явным образом, если при создании объекта требуется сразу же выполнить некоторый код, установить начальные значения его свойств или передать значения его свойств как параметры.
Формально конструктор является функцией, имя которой не произвольно, а является ключевым словом __construct(с двумя ведущими символами подчеркивания_ _) или же должно совпадать с именем класса.
Пример создания метода класса cheg с помощью ключевого слова __construct:
<?php
class cheg {
var $summa=0;
function __construct($sum) {
$this->summa = $sum;
echo "На вашем счете $sum рублей";
}
}
// Вызвать конструктор класса cheg
$object = new cheg(1000);
?>
В окне веб-браузера это будет выглядеть ТАК.
Пример альтернативного создания метода класса cheg:
<?php
class cheg{
var $summa;
function cheg($sum) {
$this->summa=$sum;
echo "На вашем счете $sum рублей";
}
}
// Вызвать конструктор класса cheg
$object = new cheg(1000);
?>
В окне веб-браузера это будет выглядеть ТАК.
Раньше создание объекта и инициализация свойств выполнялись раздельно. Конструкторы позволяют выполнить эти действия за один этап.
Интересная подробность: в зависимости от количества передаваемых параметров могут вызываться разные конструкторы. В рассмотренном примере объекты класса cheg могут создаваться двумя способами. Во-первых, вы можете вызвать конструктор, который просто создает объект, но не инициализирует его свойства:
$object = new cheg()
Во-вторых, объект можно создать при помощи конструктора, определенного в классе, — в этом случае вы создаете объект класса cheg и присваиваете значение его свойству summa:
$object = new cheg(1000)
Конструктор, ранее совпадавший с названием класса, необходимо объявлять как __construct(), что позволит легче перемещать классы в иерархиях. Конструкторы в классах-родителях не вызываются автоматически. Чтобы вызвать конструктор, объявленный в родительском классе, следует обратиться к методу parent::__construct().
Объект можно уничтожить в ходе выполнения сценария, вызвав функцию unset() и передав ей в качестве параметра имя объекта. Но в любом случае при завершении работы сценария память, занимаемая объектом, высвобождается, и объект из нее удаляется. В объектной модели РНР5 определена функция __destruct(), которая вызывается автоматически при уничтожении объекта.
Рассмотрим пример, в котором определяется конструктор и деструктор класса, а также создание объекта как экземпляра созданного класса.
<?php
class ched {
function __construct() {
print "Конструктор \n <br>";
$this->name = "ched";
}
function __destruct() {
print "Уничтожается " . $this->name. "\n <br>";
}
}
$obj = new ched();
unset($obj);
print "А теперь завершается работа сценария";
?>
В окне веб-браузера это будет выглядеть ТАК.
Неписанным правилом объектно-ориентированного программирования является использование только закрытых членов, доступ к которым осуществляется через открытые методы класса. Это позволяет скрыть внутренню реализацию класса, ограничить диапазон значений, которые можно присваивать члену, и сделать член доступным только для чтения.
Неудобство заключается в том, что для каждого из членов класса приходится создавать отдельный метод для чтения и присваивания нового значения, имена которых зачастую не совпадают с именами членов.
Выходом из ситуации является использование свойств, обращение к которым выглядет точно так же, как к открытым членам класса. Для их реализации необходимо перегрузить специальные методы __set() и __get(), которые часто называют аксессорами. Метод __get(), предназначенный для чтения свойства, принимает единственный параметр, который служит ключом. Метод __set() позволяет присвоить свойству новое значение и принимает два параметра, первый из которых является ключом, а второй — значением свойства.
Рассмотрим пример, где при помощи метода __set() объекту присваиваются новые свойства, которые помещаются в массив $this->, а перегруженный метод __get() позволяет извлечь их из массива.
Примечание. Следует обратить внимание, что методы __set() и __get() можно объявлять как закрытыми, так и открытыми.
Использование методов __set() и __get()
<?php
class cls
{
private $arr=array();
private function __get($index)
{
return $this->arr($index);
}
private function __set($index, $value)
{
$this->arr[$index]=$value;
}
}
?>
Как видно из листинга, класс cls перехватывает все обращения к членам объекта и создает соответствующий элемент в закрытом массиве $arr.
Рассмотрим пример, где обращение к члену $name приводит к созданию соответствующего элемента массива.
Обращение к несуществующему элементу $name
<?php
require_once("356.php");
//создаем объект класса
$obj=new cls();
$objt=$obj->name= "Hello world! <br>";
echo $objt;
echo "<pre>";
print_r($obj);
echo "</pre>";
?>
Любая попытка присвоить члену значение приводит к созданию нового элемента закрытого массива $arr. Когда член в классе уже существует, то аксессоры __set() и __get() перехватывают обращение к нему, если он является закрытым (имеет спецификатор доступа private), и не перехватывают, если он является открытым (public).
Наследование — это не просто создание точной копии класса, а расширение уже существующего класса, чтобы потомок мог выполнять какие-нибудь новые, характерные только ему функции.
Итак, пусть у нас есть некоторый класс Cheg с определенными свойствами и методами. Зададимся целью создать новый класс Child, как бы "расширяющий" возможности класса Cheg, добавляющий ему несколько новых свойств и методов.
Чтобы определить класс-наследник, используется такой синтаксис:
class имя_класса-наследника extends имя_класса-родителя {
определение_свойств
определение_методов
}
В объекте, созданном на основе класса имя_класса-наследника, доступны все свойства и методы класса имя_класса-родителя. Однако обратное утверждение не верно: в в объекте родительского класса свойства и методы его наследников не доступны.
<?php
class Cheg {
function cheg_funct() {
echo "<h1>Это родительская функция</h1>";
}
function test () {
echo "<h1>Это родительский класс</h1>";
}
}
class Child extends Cheg { //создание класса наследника
function child_funct() { //свойство класса
echo "<h2>Это дочерняя функция</h2>";
}
function test () { //метод класса
echo "<h2>Это дочерний класс</h2>";
}
}
$object = new Cheg;
$object = new Child;
$object->cheg_funct(); // Выводит 'Это родительская функция'
$object->child_funct(); // Выводит 'Это дочерняя функция'
$object->test(); // Выводит 'Это дочерний класс'
?>
В окне веб-браузера это будет выглядеть ТАК.