| PHP5 ещё официально не вышел, но "рабочие" версии уже трудоспособны (равно как и нестабильны!), так что мы вполне можем начать изучение новых возможностей грядущего релиза PHP и попрактиковать с ними. В этой статье мы поговорим о трёх основных нововведениях в PHP5: Новая объектная модель Исключения Пространства имён 
 Но сначала пара официальных заявлений:  Некоторые из приведённых в данной статье решений воспроизводимы в PHP4, но, тем не менее, их описание присутствует и здесь для большей удобочитаемости и целостности всей статьи. Некоторые из описанных в данной статье особенностей в конечном релизе PHP5 могут быть изменены. 
 PHP5 ещё не выпущен и мне неизвестно, когда это произойдёт, но уже сейчас вы можете потестировать и изучить новые возможности языка, скачав рабочую версию PHP5 с http://snaps.php.net и установив её. По этой ссылке вы можете найти готовые для установки Windows и Linux версии PHP5. Инсталляция проходит как у любого нормального релиза PHP, так что все бегом за новой игрушкой.  Новая объектная модельВ PHP5 объектную модель основательно подлатали и добавили много новых возможностей, благодаря чему PHP5 стал "чем-то" напоминать Java. В этой части нашей статьи будет описана эта новая объектная модель и приведено несколько небольших примеров, чтобы вам обозначить исходный рубеж для ваших экспериментов.  Конструкторы и деструкторы Объекты как ссылки Клонирование объектов Дескрипторы Private, Public и Protected Интерфейсы Абстрактные классы __call __set and __get Закрытые члены 
 Конструкторы и деструкторыВ PHP4 конструктор именуется так же как и сам класс, а деструкторы отсутствуют полностью.  В PHP5 конструктор класса именуется __construct, а деструктор - __destruct. 
 
 Пример 1: Конструкторы и деструкторы <?php class foo {
 var $x;
 
 function __construct($x) {
 $this->x = $x;
 }
 
 function display() {
 print($this->x);
 }
 
 function __destruct() {
 print("ну, пока, до скорого");
 }
 }
 
 $o1 = new foo(4);
 $o1->display();
 ?>
 Как вы видите, деструктор вызывается перед самым уничтожением класса.  Объекты как ссылкиКак вам уже наверняка известно, в PHP4 переменные передаются в функции/методы по значению (передаётся копия), если в объявлении функции не поставлен символ '&', указывающий на то, что переменная должна передаваться как ссылка. В PHP5 объекты передаются всегда как ссылки. Присваивание объектов тоже происходит по ссылке. 
 
 Пример 2: Объекты как ссылки <?php class foo {
 var $x;
 
 function setX($x) {
 $this->x = $x;
 }
 
 function getX() {
 return $this->x;
 }
 }
 
 $o1 = new foo;
 $o1->setX(4);
 $o2 = $o1;
 $o1->setX(5);
 if($o1->getX() == $o2->getX()) print("Ох ты, Боже мой!");
 ?>
 Клонирование объектовЕсли объекты присваиваются и передаются по ссылке, то вам нужно как-то создавать и копии объектов. Для этого используйте метод __clone.
 
 Пример 3: Клонирование объектов <?php class foo {
 var $x;
 
 function setX($x) {
 $this->x = $x;
 }
 
 function getX() {
 return $this->x;
 }
 }
 
 $o1 = new foo;
 $o1->setX(4);
 $o2 = $o1->__clone();
 $o1->setX(5);
 
 if($o1->getX() != $o2->getX()) print("Копии взаимонезависимы");
 ?>
 В программировании клонирование разрешено, так что всё легально ;-)  Дескрипторы Private, Public и ProtectedВ PHP4 все методы и переменные внутри объекта были доступны извне, другими словами все методы и переменные всегда были открытыми. В PHP5 вводится три дескриптора для осуществления контроля над доступом к переменным и методам: Public, Protected и Private. Public (открытый): Метод/переменная доступны из любого места в коде. 
Private (закрытый): Закрытые методы или переменные доступны только внутри класса. 
Protected (защищённый): Защищённые методы или переменные доступны только внутри класса, где они были объявлены и из его производных классов. 
 
 Пример 4: Public, protected and private <?php class foo {
 private $x;
 
 public function public_foo() {
 print("Это открытый метод");
 }
 
 protected function protected_foo() {
 $this->private_foo(); //Всё правильно, мы можем вызывать закрытые методы, потому что мы находимся в том же классе
 print("Это защищённый метод");
 }
 
 private function private_foo() {
 $this->x = 3;
 print("Это закрытый метод");
 }
 }
 
 class foo2 extends foo {
 public function display() {
 $this->protected_foo();
 $this->public_foo();
 // $this->private_foo();  // Неправильно! В базовом классе метод закрыт
 }
 }
 
 $x = new foo();
 $x->public_foo();
 //$x->protected_foo();  //Неправильно, защищённые методы могут вызываться только из того же класса или его производных классов
 //$x->private_foo();    //Неправильно, закрытые методы могут быть вызваны только в классе, где они были объявлены
 
 $x2 = new foo2();
 $x2->display();
 ?>
 Совет разработчикам: Переменные класса всегда следует делать закрытыми, прямой доступ к переменным - не очень хорошая практика в ООП, лучше всего для доступа/изменения переменных класса определять специальные методы.  ИнтерфейсыКак вы знаете, PHP4 поддерживает наследование классов синтаксисом "class foo extends parent". В PHP4 И в PHP5 класс может наследовать только один класс, то есть множественное наследование не поддерживается. Интерфейсом называется класс, в котором не реализуется ни один метод, определяются только названия методов и набор передаваемых им параметров. Впоследствии классы могут 'реализовывать' сколь угодно много интерфейсов, показывая тем самым, что тот или иной класс реализует методы, определённые в интерфейсе. 
 
 Пример 5: Интерфейсы <?php interface displayable {
 function display();
 }
 
 interface printable {
 function doprint();
 }
 
 class foo implements displayable,printable {
 function display() {
 // код
 }
 
 function doprint() {
 // код
 }
 }
 ?>
 Использование интерфейсов полезно для более удобного чтения и понимания кода: прочитав объявление класса, мы увидим, что класс реализует интерфейсы displayable и printable; это означает, что класс должен иметь методы display() и doprint(). Как эти методы реализованы - значения не имеет, главное - уже из объявления класса, вы знаете, что можете вызывать эти методы.  Абстрактные классыАбстрактным называется класс, который может использоваться только как базовый (то есть создавать объекты этого класса нельзя). Как и в любом нормальном базовом классе, в абстрактном классе вы можете определять методы и переменные.  В абстрактном классе также можно определять абстрактные методы: методы, которые не реализованы в абстрактном классе, но которые обязательно должны быть реализованы в производных классах. 
 
 Пример 6: Абстрактные классы <?php abstract class foo {
 protected $x;
 
 abstract function display();
 
 function setX($x) {
 $this->x = $x;
 }
 }
 
 
 class foo2 extends foo {
 function display() {
 // Код
 }
 }
 ?>
 
 __callС PHP5 вы можете реализовать в классе специальный метод __call(), как метод для "отлова" всех нереализованных в данном классе методов. Метод __call (если он определён) вызывается при попытке вызвать недоступный или несуществующий метод. 
 
 Пример 7: __call  <?php class foo {
 
 function __call($name,$arguments) {
 print("Вызывали? Я -  $name!");
 }
 }
 
 $x = new foo();
 $x->doStuff();
 $x->fancy_stuff();
 ?>
 Этот специальный метод может быть использован для реализации перегрузки методов: вы можете исследовать полученные аргументы и в зависимости от результата вызвать подходящий для данного случая закрытый метод, например: 
 
 Пример 8: Перегрузка методов с помощью __call <?php class Magic {
 
 function __call($name,$arguments) {
 if($name=='foo') {
 if(is_int($arguments[0])) $this->foo_for_int($arguments[0]);
 if(is_string($arguments[0])) $this->foo_for_string($arguments[0]);
 }
 }
 
 private function foo_for_int($x) {
 print("у, смотрите, целое число!");
 }
 
 private function foo_for_string($x) {
 print("у, смотрите, строка!");
 }
 }
 
 $x = new Magic();
 $x->foo(3);
 $x->foo("3");
 ?>
 __set и __get Но это ещё не всё, теперь вы можете определить методы __set и __get для "отлова" всех попыток изменения или доступа к неопределённым (или недоступным) переменным. 
 
 Пример 9: __set и __get <?php class foo {
 
 function __set($name,$val) {
 print("Привет, вы попытались присвоить значение $val переменной $name");
 }
 
 function __get($name) {
 print("Привет, вы пытались обратиться к $name");
 }
 }
 
 $x = new foo();
 $x->bar = 3;
 print($x->winky_winky);
 ?>
 
 Указание типов для аргументовВ PHP5 вы сможете "сказать" методу, что он должен получить в качестве аргумента объект определённого типа. 
 
 Пример 10: указание типов <?php class foo {
 // код ...
 }
 
 class bar {
 public function process_a_foo(foo $foo) {
 // Ещё какой-нибудь код
 }
 }
 
 $b = new bar();
 $f = new foo();
 $b->process_a_foo($f);
 ?>
 Как вы заметили, перед именем аргумента теперь можно поставить имя его класса, и таким образом PHP5 определит, что переменная $foo должна быть класса foo.  Статические члены классаСтатические члены и статические методы могут использоваться для реализации того, что в ООП называется "методы класса" и "переменные класса".  "Статическим методом класса" называют метод, который можно вызвать без создания объекта этого класса. "Переменной класса" называют переменную, к которой можно обратиться без создания объекта этого класса (и метод доступа при этом не потребуется).
 
 
 Пример 11: методы класса и переменные класса <?php class calculator {
 static public $pi = 3.14151692;
 
 static public function add($x,$y) {
 return $x + $y;
 }
 }
 
 $s = calculator::$pi;
 $result = calculator::add(3,7);
 print("$result");
 ?>
 
 ИсключенияИсключения - это общепринятый подход к обработке ошибок и неожиданных ситуаций в таких языках как Java и C++; в PHP5 перехват исключений реализован с помощью пары "try" - "catch". 
 
 Пример 12: Исключения <?php class foo {
 
 function divide($x,$y) {
 if($y==0) throw new Exception("деление на ноль недопустимо");
 return $x/$y;
 }
 }
 
 $x = new foo();
 
 try {
 $x->divide(3,0);
 } catch (Exception $e) {
 echo $e->getMessage();
 echo "\n<br />\n";
 // Какие-нибудь драконовские меры
 }
 ?>
 Как вы видите, "try" используется для обозначения блока, в котором находятся ошибки, обрабатываемые оператором "catch", стоящим в конце блока. В блоке "catch" вам нужно реализовать вашу собственную политику обработки ошибок. В итоге получаем удобочитаемый код и всего один блок обработки ошибок. 
 Исключения, определённые пользователем Для обработки непредвиденных проблем в ваших программах вы можете определить ваши собственные исключения. Всё, что вам нужно - это просто дополнить (extend) класс Exception, определив конструктор класса и метод getMessage. 
 
 Пример 13: Исключения, определённые пользователем  <?php class WeirdProblem extends Exception {
 
 private $data;
 
 function WeirdProblem($data) {
 parent::exception();
 $this->data = $data;
 }
 
 function getMessage() {
 return $this->data . " вызвало какое-то странное исключение!";
 }
 }
 ?>
 Потом, для возбуждения определённого вами исключения используйте конструкцию throw new WeirdProblem($foo); если исключение происходит внутри блока try{}, то PHP5 передаст управление в "catch"-блок для обработки.  Пространства имёнВ целях удобства классы и функции могут быть сгруппированы в пространства имён (namespaces).  Примечение: разработчики отказались от поддрежки этой возможности. 
 
 Пример 14: Пространство имён <?php namespace Math {
 
 class Complex {
 //...код...
 function __construct() {
 print("привет");
 }
 }
 }
 
 $m = new Math::Complex();
 ?>
 Обратите внимание на синтаксис использования именного пространства для обозначения класса, объект которого мы создаём. Пример практического применения: создание одноимённых классов в разных именных пространствах; при этом классы делают отличную друг от друга работу (имея одинаковый интерфейс). 
 |