Объектно-ориентированное программирование в PHP
Классы содержат в себе члены класса, которые представляют собой свойства и методы. Свойства класса - это переменные, а методы класса - это функции, которые взаимодействуют со свойствами.
Объявляются свойства (переменные) с помощью служебного слова var и имени переменной $per , а методы (функции) пишутся как простые функции.
Обращение к классу происходит через объявление объекта с помощью служебного слова new и имя класса.
class Gena
{
var $per='Свойство (переменная) класса Gena<br>';
function f1()
{
echo 'Метод (функция) класса Gena';
}
}
$obj=new Gena;
echo $obj->per; // Свойство (переменная) класса Gena
$obj->f1(); // Метод (функция) класса Gena
public - Доступ к типу или члену возможен из любого другого кода в той же сборке или другой сборке, ссылающейся на него.
private - Доступ к типу или члену можно получить только из кода в том же классе или структуре.
protected - Доступ к типу или элементу можно получить только из кода в том же классе или структуре, либо в производном классе.
internal - Доступ к типу или члену возможен из любого кода в той же сборке, но не из другой сборки.
Все свойства (Переменные) по умолчанию public (var - устарело)
Все методы (Функции) по умолчанию public и static
Инкапсуляция
Инкапсуляция - это механизм, объединяющий данные и обрабатывающий их код как единое целое.
Инкапсуляцией называется включение различных мелких элементов в более крупный объект, в результате чего программист работает непосредственно с этим объектом.
class Gena
{
private $a='Гена';
function f1()
{
return $this->a;
}
}
$obj=new Gena;
//echo $obj->a; // НЕЛЬЗЯ!!!
echo $obj->f1(); // Гена
ООП — скрывает от программиста лишние коды, что позволяет ему сосредоточиться на решении общих задач. В ООП эта возможность обеспечивается классами, объектами и различными средствами выражения иерархических связей между ними.
Наследование
Наследование позволяет одному объекту приобретать свойства другого объекта, не путайте с копированием объектов. При копировании создается точная копия объекта, а при наследовании точная копия дополняется уникальными свойствами, которые характерны только для производного объекта.
class Gena
{
public $a='Гена';
function f1($b)
{
return"$b, $this->a";
}
}
class Gena2 extends Gena
{
}
$obj=new Gena2;
$obj->a='Вова'; // Изменяем свойство
echo $obj->f1('Привет'); // Привет, Вова
или
class Gena1
{
public $a='Гена';
function f1($b)
{
return"$b, $this->a";
}
}
class Gena2 extends Gena1
{
}
class Gena3 extends Gena2
{
}
$obj=new Gena3;
$obj->a='Вова'; // Изменяем свойство
echo $obj->f1('Привет'); // Привет, Вова
Полиморфизм
Полиморфизм в php позволяет использовать одни и те же имена для похожих, но технически разных задач. Главным в полиморфизме является то, что он позволяет манипулировать объектами путем создания стандартных интерфейсов для схожих действий. Полиморфизм значительно облегчает написание сложных программ.
class A
{
function Test() // Выводит, функция какого класса была вызвана
{
echo "class A - Test <br>\n";
}
function Call() // Тестовая функция — просто переадресует на Test()
{
$this->Test();
}
}
class B extends A
{
function Test() // Функция Test() для класса B
{
echo "class B - Test <br>\n";
}
}
$a=new A();
$b=new B();
$a->Test(); // class A - Test
$b->Test(); // class B - Test
$b->Call(); // class B - Test Внимание!!!
Обращение к свойствам и методам внутри класса осуществляется через $this-> (тире и больше).
class Gena
{
var $per='Свойство Gena<br>';
function f1()
{
return'Функция и '.$this->per;
}
}
$obj=new Gena;
echo $obj->f1(); // Функция и Свойство Gena
Иногда требуется автоматически инициализировать данные сразу при обращении к классу (при создании объекта), для этого используют конструкторы. Конструктор - это авто-запускающаяся функция, которая имеет одинаковое название с классом или зарезервированное имя __construct()
class Gena
{
function __construct()
{
echo 'Авто запуск';
}
}
$obj=new Gena; // Авто запуск
Функции конструктору можно передать аргумент при создании объекта.
class Gena
{
function Gena($a)
{
echo 'Авто запуск + '.$a;
}
}
$obj=new Gena('Аргумент'); // Авто запуск + Аргумент
Конструкторы в классах-родителях не вызываются автоматически. Чтобы вызвать конструктор, объявленный в родительском классе, следует обратиться к методу parent::__construct().
class Gena
{
function __construct()
{
echo "Конструктор класса Gena<br>\n";
}
}
class Roma extends Gena
{
function __construct()
{
parent::__construct();
echo "Конструктор класса Roma<br>\n";
}
}
$obj=new Gena(); // Конструктор класса Gena
$obj=new Roma(); // Конструктор класса Gena Конструктор класса Roma
Если PHP 5 не может обнаружить объявленный метод __construct(), вызов конструктора произойдет по прежней схеме, через обращение к методу, имя которого соответствует имени класса. Может возникнуть только одна проблема совместимости старого кода, если в нём присутствуют классы с методами __construct().
PHP 5 предоставляет концепцию деструкторов, сходную с теми, что применяются в других ОО языках, таких, как Java: когда освобождается последняя ссылка на объект, перед высвобождением памяти, занимаемой этим объектом, вызывается метод __destruct(), не принимающий параметров.
class Gena
{
function __construct()
{
echo "Конструктор<br>\n";
$this->name="<b>всё</b>";
}
function __destruct()
{
echo 'Уничтожается '.$this->name."<br>\n";
}
}
$obj=new Gena(); // Конструктор Уничтожается Всё
Как и в случае с конструкторами, деструкторы, объявленные в родительском классе, не будут вызваны автоматически. Для вызова деструктора, объявленном в классе-родителе, следует обратиться к методу parent::__destruct().
А в php4 : Необходимость в вызове деструкторов возникает лишь при работе с объектами, использующими большой объем ресурсов, поскольку все переменные и объекты автоматически уничтожаются по завершении сценария, но можно использовать unset() - удалить переменную.
Наследование производится с помощью служебного слова extends
class Gena
{
function f1($a)
{
echo $a;
}
}
class Roma extends Gena
{
}
$obj=new Roma;
$obj->f1('Аргумент'); // Аргумент
Или константы, которые обозначаются служебным словом const переменные, которые маркируются служебным словом static
class Gena
{
const CON='Значение константы<br>';
static $per='Статическая переменная<br>';
}
echo Gena::CON; // Значение константы
echo Gena::$per; // Статическая переменная
Ни к const ни к static нельзя обратится через ->
Для обращения к свойствам и методам в объявлении класса используются ключевые слова self и parent. Пример использования :: в объявлении класса:
class Gena
{
const CON='Значение константы<br>';
}
class Rita extends Gena
{
static $per='Статическая переменная<br>';
function f_1()
{
echo parent::CON;
echo self::$per;
}
}
Rita::f_1(); // Значение константы Статическая переменная
Все Методы (функции) в классе по умолчанию public и static
Все Свойства (переменные) в классе по умолчанию public
Полиморфизм (многоформенность) является следствием идеи наследования.
class Gena
{
function f_1()
{
echo "<h2>Функция базового класса</h2>";
}
function f_2()
{
$this->f_1();
}
}
class Vera extends Gena
{
function f_1()
{
echo "<h3>Функция производного класса</h3>";
}
}
$g=new Gena();
$v=new Vera();
$g->f_2(); // Функция базового класса
$v->f_1(); // Функция производного класса
$v->f_2(); // Функция производного класса
Обращаясь к одной и той же функции f_2() - из разных объектов получаем разный результат, по сути мы используем разные функции - в этом сущность полиморфизма
class K_1
{
function f_1()
{
echo 123;
}
function f_2()
{
$this->f_1();
}
}
class K_2 extends K_1
{
function f_1()
{
echo 456;
}
}
$o_1=new K_1;
$o_2=new K_2;
$o_1->f_2(); // 123
$o_2->f_2(); // 456
Копирование объектов
class K_1
{
function f_1()
{
echo 123;
}
}
$o_1=new K_1;
$o_2=$o_1;
$o_2->f_1(); // 123
Сравнение объектов
class K_1
{
function f_1()
{
echo 123;
}
}
$o_1=new K_1;
$o_2=new K_1;
if ($o_1==$o_2) {echo 'Объекты равны';} // Объекты равны
public/private/protected - модификаторы доступа для методов и свойств для php5
- Модификатор public позволяет обращаться к свойствам и методам отовсюду.
- Модификатор private позволяет обращаться к свойствам и методам только внутри текущего класса.
- Модификатор protected позволяет обращаться к свойствам и методам только текущего класса и класса, который наследует свойства и методы текущего класса.
Создание копии объекта с абсолютно идентичными свойствами не всегда является приемлемым вариантом. Например, когда ваш объект содержит ссылку на какой-либо другой используемый объект и, когда вы создаёте копию ссылающегося объекта, вам нужно также создать новый экземпляр содержащегося объекта, так, чтобы копия объекта содержала собственный отдельный экземпляр содержащегося объекта.
class Gena
{
public $r='Красный<br>';
}
$obj=new Gena();
$obj2=$obj;
$obj->r='Зелёный<br>';
echo $obj->r; // Зелёный
echo $obj2->r; // Зелёный
Копия объекта создается с использованием вызова clone (который вызывает метод __clone() объекта, если это возможно). Вы можете объявить метод __clone(), который будет вызван при клонировании объекта (после того, как все свойства будут скопированы из исходного объекта).
class Gena
{
public $r='Красный<br>';
}
$obj=new Gena();
$obj2=clone $obj;
$obj->r='Зелёный<br>';
echo $obj->r; // Зелёный
echo $obj2->r; // Красный
Когда программист запрашивает создание копии объекта, PHP 5 определит, был ли для этого объекта объявлен метод __clone() или нет. Если нет, будет вызван метод __clone(), объявленный по умолчанию, который скопирует все свойства объекта. Если метод __clone() был объявлен, создание копий свойств в копии объекта полностью возлагается на него. Для удобства, движок обеспечивает программиста функцией, которая импортирует все свойства из объекта-источника, так что программист может осуществить позначное копирование свойств и переопределять только необходимые. Приведем пример клонирования объекта:
class Car
{
public $year='2011';
public $speed;
public $model;
function __construct($m, $s)
{
$this->model=$m;
$this->speed=$s;
}
function __destruct()
{
echo "Объект удален!";
}
function __clone()
{
$this->year='1965';
$this->model='vaz';
$this->speed=90;
}
function getInfo()
{
echo "Модель=".$this->model."<br />";
echo "Скорость=".$this->speed."<br />";
echo "Год=".$this->year."<br /><br />";
}
}
$car1=new Car('opel',100);
$car1->getInfo();
$car2=new Car('audi',120);
$car2->year=2009;
$car2->getInfo();
$car3=clone $car1;
$car3->getInfo();
/*
Модель=opel
Скорость=100
Год=2011
Модель=audi
Скорость=120
Год=2009
Модель=vaz
Скорость=90
Год=1965
Объект удален!Объект удален!Объект удален!
*/
Получилось:
Модель = opel
Скорость = 100
Год = 2011
Модель = audi
Скорость = 120
Год = 2009
Модель = vaz
Скорость = 160
Год = 1965
Объект удален!Объект удален!Объект удален!
Константы класса
В определения классов теперь можно включить константы, и ссылаться на них, используя объект. Константы также могут быть объявлены и в пределах одного класса. Отличие переменных и констант состоит в том, что при объявлении последних или при обращении к ним не используется символ $. Как и свойства и методы, значения констант, объявленных внутри класса, не могут быть получены через переменную, содержащую экземпляр этого класса.
class Gena
{
const CON="Константа";
}
echo Gena::CON; // Константа
Статические члены класса
Определения классов могут теперь включить статических членов класса (свойства и методы), доступ к которым осуществляется через класс. Общее использование статических членов показано на примере:
class Singleton
{
static private $instance=NULL;
private function __construct()
{
}
static public function getInstance()
{
if (self::$instance==NULL)
{
self::$instance = new Singleton();
}
return self::$instance;
}
}
Статические методы
Вы можете теперь определить методы как статические, разрешая им быть вызванными вне контекста объекта. Статические методы не определяются через переменную $this, поскольку они не должны быть ограничены определенным объектом.
class Gena
{
static function f_1()
{
echo "Привет, мир!";
}
}
Gena::f_1(); // Привет, мир!
Абстрактные классы
PHP 5 поддерживает определение абстрактных классов и методов. Создавать экземпляр класса, который был объявлен абстрактным, нельзя. Класс, в котором объявлен хотя бы один абстрактный метод, должен также быть объявлен абстрактным. Методы, объявленные как абстрактные, несут, по существу, лишь описательный смысл и не могут включать какой-либо функционал. Класс может быть объявлен как абстрактный при помощи использования ключевого слова abstract, для исключения из обработки движком описания класса. Однако, вы можете наследовать абстрактные классы. Практический пример:
abstract class Gena
{
public $r='Красный';
}
class Petya extends Gena
{
}
$o=new Petya;
echo $o->r; // Красный