Web - кодинг: PHP:
Введение в PHP5
Автор: Luis Argerich
Перевод: Данил Миронов
PHP5 ещё официально не вышел, но "рабочие" версии
уже трудоспособны (равно как и нестабильны!), так что мы вполне
можем начать изучение новых возможностей грядущего релиза PHP и
попрактиковать с ними. В этой статье мы поговорим о трёх основных
нововведениях в PHP5:
- Новая объектная модель
- Исключения
- Пространства имён
Но сначала пара официальных заявлений:
- Некоторые из приведённых в данной статье
решений воспроизводимы в PHP4, но, тем не менее, их описание
присутствует и здесь для большей удобочитаемости и целостности
всей статьи.
- Некоторые из описанных в данной статье особенностей в конечном
релизе PHP5 могут быть изменены.
PHP5 ещё не выпущен и мне неизвестно, когда это
произойдёт, но уже сейчас вы можете потестировать и изучить новые
возможности языка, скачав рабочую версию PHP5 с
и установив её. По этой ссылке вы можете найти готовые для установки
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(); ?>
Обратите внимание на синтаксис использования
именного пространства для обозначения класса, объект которого мы
создаём. Пример практического применения: создание одноимённых
классов в разных именных пространствах; при этом классы делают
отличную друг от друга работу (имея одинаковый интерфейс).
При перепечатке любого материала
с сайта, видимая ссылка на источник www.warayg.narod.ru
и все имена, ссылки авторов обязательны.
© 2005
|