ООП в PHP
Основная конструкция и модификаторы в ООП PHP
В ООП есть модификаторы доступа к свойствам (переменным) и методам функциям):
public или var (свойства, методы) - полный доступ
private (свойства, методы) - только из собственного класса
protected (свойства, методы) - только из собственного класса и класса наследника
internal - полный доступ, только из одной сборки (без include и др.) - используется редко
Все свойства (переменные) по умолчанию public (var)
Все методы (функции) по умолчанию public и static
Обращаться к свойствам (переменным) и метода (функциям) внутри класса нужно через $this->a;
Пр:
class Gena
{
//var $a='Гена'; // одно и тоже
public $a='Гена';
function f1()
{
return 'Привет, '.$this->a;
}
}
$ob=new Gena;
//echo $ob->a; // Гена
echo $ob->f1(); // Привет, Гена
К функциям (они по умолчанию static) и свойствам (обязательно указывать static) - можно обращаться без создания объекта через ::
Пр:
class Gena
{
public static $i=2;
const CON=8;
function f1($a)
{
echo $a;
}
}
Gena::f1('Геннадий'); // Геннадий
echo Gena::$i; // 2
echo Gena::CON; // 8
Для РАСШИРЕНИЯ касса используют extends.
Пр: class Gena2 extends Gena {} - нов. (дочерний) класс Gena2 расширяется классом Gena. Класс Gena2 получает все свойства и методы из класса Gena их можно переназначить в дочернем классе (Gena2)
Для объявления КОНСТАНТ используем служебное слово const. Ни к const ни к static нельзя обратится через ->
Для обращения к свойствам и методам класса, используются ключевые слова self (внутри класса) и parent (к родительским классам). Пример использования extends (расширения) и :: в объявлении класса:
Пр:
class MyClass
{
function __call($name, $params)
{
echo "Вызван метод $name с параметром $params[0]";
}
}
$obj = new MyClass;
echo $obj->method(1); // Вызван метод method с параметром 1
Специальные функции __construct($a) и __destruct()
function __construct($a) - функция КОНСТРУКТОР, автоматически запускается при создании объекта $ob=new Gena($a), можно передавать аргументы. function __construct($a) можно заменить на имя класса function Gena($a).
Родительский __construct, можно запрашивать в дочернем, только через parent::__construct($a);
Пр:
class Gena
{
const CON='Константа ';
}
class Gena2 extends Gena
{
function __construct($a)
{
echo $a;
}
}
$ob=new Gena2('Гена'); // Гена
function __destruct() - функция ДЕСТРУКТОР удаляет весь объект (освобождает память), но после отработки кода все объекты и так автоматически уничтожаются. По аналогии можно использовать parent::__destruct(), но можно использовать и unset() - удаление переменной.
Клонирование объектов
Если написать $ob2=$ob; (это link) - $ob2 означает ссылку на объект $ob. Если изменить один объект - изменяется и другой. Для клонирования (создания др. такого же объекта) нужно использовать ключевое слово clone
Пр:
class Gena
{
public $a=1;
}
$ob=new Gena;
$ob2=clone $ob;
$ob2->a=2;
echo $ob->a; // 1
echo $ob2->a; // 2
Можно создать метод клон, function __clone(), он будет автоматически срабатывать при клонировании.
Пр:
class Gena
{
public $a=1;
function __clone()
{
$this->a=2;
}
}
$ob=new Gena;
$ob2=clone $ob;
echo $ob->a; // 1
echo $ob2->a; // 2
Метод с ключевым словом final, не может быть переопределен в дочерних классах. Класс с ключевым словом final не могут иметь наследников.
Абстрактные классы (abstract class Gena) - классы которые не могут иметь объекты. Объекты могут иметь только их наследники.
Абстрактный метод ( abstract public function f1(){} ) может находится только в абстрактном классе.
Основное отличие интерфейсов от абстрактных классов заключается в том, что в PHP 5 класс не может быть порожден от нескольких классов, в том числе и абстрактных, но зато может быть создан на основе любого числа интерфейсов.
При этом в интерфейсе методы объявляются ключевым словом function без указания каких-либо спецификаторов, в том числе и abstract.
Пр:
interface Int1
{
function func1();
}
interface Int2
{
function func2();
}
class MyClass implements Int1, Int2
{
public function func1()
{
echo 'Вася -';
}
public function func2()
{
echo ' друг!';
}
}
$obj=new MyClass;
$obj->func1(); // Вася -
$obj->func2(); // друг!
Таким образом, хотя множественное наследование (multiple inheritance) и не поддерживается в PHP 5, разработчики получили реальную возможность создавать классы на основе отдельно описанных интерфейсов.
Специальное ключевое слово instanceof в PHP 5 позволяет определять является ли объект экземпляром определенного класса, или же экземпляром класса производного от какого-либо другого класса.
Пр:
class MyClass {}
$obj1=new MyClass();
if ($obj1 instanceof MyClass)
{
echo "\$obj1 - объект класса MyClass<br>\n";
}
class MyClass1 extends MyClass {}
$obj2=new MyClass1();
if ($obj2 instanceof MyClass)
{
echo "\$obj2 - объект класса, производного от MyClass<br>\n";
}
interface Int {}
class MyClass2 implements Int {}
$obj3 = new MyClass2();
if ($obj3 instanceof Int)
{
echo "\$obj3 - объект класса, созданного на основе интерфейса Int<br>\n";
}
/*
$obj1 - объект класса MyClass
$obj2 - объект класса, производного от MyClass
$obj3 - объект класса, созданного на основе интерфейса Int
*/
Также с помощью instanceof можно определить является ли объект экземпляром класса, созданного на основе определенного интерфейса.
Специальная функция __autoload() будет вызываться в PHP 5 в случае попытки создания объекта неопределенного класса.
Пр:
function __autoload($class)
{
echo "попытка создать объект неопределенного класса ", $class;
}
$obj=new MyClass;
В качестве параметра функции __autoload() передается имя неопределенного класса.
В PHP 5 возможна перегрузка доступа к свойствам объектов.
Пр:
class MyClass
{
private $properties;
function __set($name, $value)
{
echo "задание нового свойства $name = $value<br>\n";
$this->properties[$name]=$value;
}
function __get($name)
{
echo "чтение значения свойства $name<br>\n";
return $this->properties[$name];
}
}
$obj=new MyClass;
$obj->property=1; // задание нового свойства property = 1
$a=$obj->property; // чтение значения свойства property
echo $a; // 1
Новые методы доступа __get() и __set() позволяют легко проводить динамическое назначение свойств объектам. В качестве параметров этим методам передаются имена свойств.
Метод __set() также получает и значение, которое устанавливается для свойства.
При вызове в PHP 5 несуществующего метода объекта автоматически вызывается специальный метод __call().
Пр:
class MyClass
{
function __call($name, $params)
{
echo "Вызван метод $name с параметром $params[0]";
}
}
$obj = new MyClass;
echo $obj->method(1); // Вызван метод method с параметром 1
В качестве параметров __call() принимает имя вызываемого метода и передаваемые этому методу параметры.
В PHP 5 возможен полный перебор всех свойств объекта в операторе foreach.
Пр:
class MyClass
{
public $a = 1;
public $b = 2;
}
$obj=new MyClass;
foreach ($obj as $name => $value)
{
echo "$name => $value "; // a => 1 b => 2
}
Специальные интерфейсы PHP 5 IteratorAggregate и Iterator позволяют указывать поведение класса при его использовании с оператором foreach.
В PHP 5 псевдо-константа __METHOD__ возвращает имя класса и вызываемый метод.
Пр:
class MyClass
{
public function myMethod()
{
echo "вызов метода ".__METHOD__."<br>\n";
}
}
$obj=new MyClass;
$obj->myMethod(); // вызов метода MyClass::myMethod
function myFunction()
{
echo "вызов функции ".__METHOD__."<br>\n";
}
myFunction(); // вызов функции myFunction
При обращении к функции вне класса __METHOD__ возвращает только имя функции.
В PHP 5 введен еще один специальный метод класса - __toString().
Пр:
class MyClass
{
function __toString()
{
return "вызван метод __toString()";
}
}
$obj=new MyClass;
echo $obj; // вызван метод __toString()
Метод класса __toString() позволяет выполнить перегрузку преобразования объекта в строку.
В PHP 5 введена возможность разыменования (dereferencing) объектов, которые возвращаются функциями.
Пр:
class MyClass1
{
public function showClassName()
{
echo "объект класса MyClass1<br>\n";
}
}
class MyClass2
{
public function showClassName()
{
echo "объект класса MyClass2<br>\n";
}
}
function deref($obj)
{
switch ($obj)
{
case "MyClass1":return new MyClass1();
case "MyClass2":return new MyClass2();
}
}
deref("MyClass1")->showClassName(); // объект класса MyClass1
deref("MyClass2")->showClassName(); // объект класса MyClass2
Данный механизм позволяет вызывать методы объектов, имена классов которых возвращаются пользовательскими функциями.
В PHP 5 реализованы специальные встроенные классы (Reflection API), которые позволяют анализировать классы и объекты с целью определения методов, свойств и интерфейсов, которые они поддерживают.
Пр:
class MyClass
{
public $property;
function myFunc($name)
{
echo $name;
}
}
ReflectionClass::export("MyClass");
ReflectionObject::export(new MyClass);
ReflectionMethod::export("MyClass", "myFunc");
ReflectionProperty::export("MyClass", "property");
ReflectionExtension::export("standard");
С помощью класса ReflectionExtension аналогичным образом возможен анализ расширений (extensions) PHP 5.
Закрепляем конструкцию ООП в PHP
class Человек
{
private $имя;
public function __construct($имя)
{
$this->имя = $имя;
}
public function чихнуть()
{
echo $this->имя, " чихнул<br>\n";
}
public function сказать($что)
{
echo $this->имя, ': - ', $что, "<br>\n";
}
}
$иванов = new Человек("Иванов");
$сидоров = new Человек("Сидоров");
$иванов->чихнуть();
$сидоров->сказать('Будь здоров!');
$иванов->сказать('Спасибо...');
Ещё несколько примеров:
<h1>Наследование</h1>
<?php
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('Привет'); // Привет, Вова
?>
<h1>Инкапсуляция</h1>
<?php
class Gena4
{
private $a='Гена';
function f1()
{
return $this->a;
}
}
$obj=new Gena4;
//echo $obj->a; // НЕЛЬЗЯ!!!
echo $obj->f1(); // Гена
?>
<h1>Полиморфизм</h1>
<?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 Внимание!!!
?>
<h1>Абстрактный класс</h1>
<?php
abstract class Dad
{
public function SayHi() {
return "Привет!";
}
abstract public function SayHello();
}
class Son extends Dad
{
public function SayHello() {
return "Здорово!";
}
}
$son = new Son;
echo $son->SayHello().' - '.$son->SayHi();
?>
<h1>Интерфейсы</h1>
<?php
interface Planes{
public function TakeOff(); // взлёт
public function Landing(); // посадка
}
interface Planes2{
public function Polet(); // полет
}
class Boing implements Planes, Planes2{
public function TakeOff()
{
return "Взлёт"; // Реализуем метод TakeOff() интерфейса Planes.
}
public function Landing()
{
return "Посадка"; // Реализуем метод Landing() интерфейса Planes.
}
public function Polet()
{
return "Полет"; // Реализуем метод Polet() интерфейса Planes2.
}
}
$obj=new Boing;
//echo $obj->Landing(); // Посадка
echo $obj->Polet(); // Посадка
//echo Boing::TakeOff(); // Взлёт
?>
<h1>Использование методов __set() и __get()</h1>
<?php
class cls
{
private $a='Привет!';
function __get($index)
{
return $this->a;
}
function __set($index, $value)
{
$this->$index=$value;
}
}
class cls2 extends cls
{
}
$obj=new cls2();
echo $obj->a."<br>\n";// Привет!
echo $obj->a='Пока!'; // Пока!
?>
Шахматная доска
<!DOCTYPE HTML><html dir="ltr" lang="ru-ru">
<head>
<meta charset="utf-8">
<title>Уроки PHP</title>
<style>
.cen {text-align:center;}
table {border-collapse:collapse;}
table.doska {margin:10px auto;}
table.doska td {border:1Px solid #000; width:25px; height:25px; text-align:center; font-size:9px;}
table.doska td.bel {background:#fff; color:#000;}
table.doska td.che {background:#000; color:#fff;}
</style>
</head></body>
<h1 class="cen">Шахматная доска</h1>
<?php
class Doski
{
private function doska($n)
{
$r="\n\n<table class='doska'>\n";
for($iv=1; $iv<=$n; $iv++)
{
$r.="<tr>";
if ($iv%2==0){$kl='bel';}else{$kl='che';}
for ($ig=1; $ig<=$n; $ig++)
{
if ($kl=='che'){$kl='bel';}else{$kl='che';}
$r.="<td class='$kl'>";
$r.="$iv$ig";
$r.="</td>";
}
$r.="<tr>\n";
}
return $r.="</table>\n\n";
}
public function krat($n=8,$i=1)
{
for($j=1;$j<=$i;$j++)
echo $this->doska($n++);
}
}
$ob=new doski();
$ob->krat(1,8);
?>
</head><body>