Рубрика:
Программирование /
Веб-программирование
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
КИРИЛЛ СУХОВ
PHP 5 – пришествие неизбежно
Появление PHP5 – эволюционное, а не революционное событие.
Расмус Лердорф, автор и первый разработчик PHP
Итак, свершилось. 13 июля 2004 г. вышла пятая версия самого популярного на сегодняшний день языка веб-разработки – PHP. Его создатель, Расмус Лердорф, подчёркивает, что изменения, привнесённые в язык, не революционны, а скорее эволюционны, но беглое знакомство с новыми возможностями PHP заставляет усомниться в словах мэтра. За недолгое время своего существования PHP из набора скриптов для придания интерактивности домашней странички автора сумел вырасти в мощное средство разработки веб-приложений и теперь – новый шаг вперед. Насколько этот шаг важен и какие последствия перехода на новую версию грозят программисту и системному администратору, можно оценить, ознакомившись с основными нововведениями PHP 5 и возможными проблемами, связанными с его использованием.
Объектная модель
Наиболее радикальные изменения языка связаны с введением новой объектной модели – Zend Engine II.
Формально элементы ООП появились ещё до выхода четвёртой версии PHP и были значительно расширены в пятой. Объектно-ориентированная модель позволяла работать с классами и объектами, объединяя методы и свойства, поддерживала наследование, но имела весьма серьёзные ограничения. Прежде всего это необходимость при каждом использовании объекта обращаться к нему по ссылке, в противном случае получалась его копия, и при любом изменении объекта или его свойств происходило копирование в новый объект. Поясню на примере:
<?php
class foo {
var $name;
function getName() {
return $this->name;
}
function setName($name) {
$this->name = $name;
}
function foo($name) {
$this->setName($name);
}
}
function changeName($person, $name) {
$foo->setName($name);
}
$person = new foo("Bill");
changeName($person, "John");
print $person->getName();
?>
В РНР 4 этот код выведет «Bill». Дело в том, что мы передаем объект $person в функцию changeName() по значению, а не по ссылке, таким образом, объект $person будет скопирован, и changeName() будет работать уже с копией объекта $person.
В PHP 5 объектная модель была полностью переписана, и работа теперь осуществляется с указателями на объект. Нет необходимости явно передавать объекты или присваивать их по ссылке, всё происходит автоматически. Впрочем, явная передача и присваивание по ссылке также поддерживается, более того, введён новый метод _clone(), который можно использовать, в случае если возникает необходимость клонировать объект.
<?
class foo {
function __clone() {
print "Cloned!";
}
}
$obj =new foo();
clone $obj;
?>
Разумеется, на этом нововведения не закончились. Появилась полноценная реализация конструкторов и деструкторов классов (__constuct, __destruct), стали доступны модификаторы Private, Public, Protected; (В PHP 4 все методы и переменные внутри объекта были открытыми), введены абстрактные классы (то есть классы, используемые только как базовые).
Появились специальные методы (__call, __get, __set), предназначенные для «отлова» всех нереализованных в данном классе методов, попыток изменения или доступа к неопределённым (или недоступным) переменным. Открылась возможность передать методу тип передаваемого аргумента.
<?php
function expectsMyClass(MyClass $obj) {
}
?>
Хотя множественное наследование в стиле С++ в PHP 5 не поддерживается, классы могут наследовать множественные контакты через ещё одно нововведение – интерфейсы. Естественно, программистам, знакомым с Java, объяснять, что это такое, не надо, для остальных приведу пример:
<?php
interface Display {
function display();
}
class Circle implements Display {
function display() {
print "Displaying circle ";
}
}
?>
(Класс может наследовать только один класс, но при этом иметь столько интерфейсов, сколько потребуется)
Стал ли после всего вышеописанного PHP объектно-ориентированным языком? На мой взгляд, сама постановка вопроса неправомерна. Как сказал по этому поводу Стерлинг Хьюз (один из разработчиков PHP, автор книги PHP Developer`s Cookbook): «Тяжело определить «настоящую объектность», так как у каждого есть своё мнение на этот счёт».
Обработка исключений
Мне кажется, это одно из самых полезных новшеств PHP 5. Механизм обработки исключений реализован за счёт конструкций try/catch/throw и позволяет значительно упростить код, разместив все обработчики ошибок в одном месте. Кроме того, предусмотрена возможность определять собственные исключения. Делается это посредством расширения класса Exception, определив его конструктор и метод getMessage:
<?php
class Exception {
function __construct(string $message=NULL, int $code=0) {
if (func_num_args()) {
$this->message = $message;
}
$this->code = $code;
$this->file = __FILE__; // of throw clause
$this->line = __LINE__; // of throw clause
$this->trace = debug_backtrace();
$this->string = StringFormat($this);
}
protected $message = 'Unknown exception'; // exception message
protected $code = 0; // user defined exception code
protected $file; // source filename of exception
protected $line; // source line of exception
private $trace; // backtrace of exception
private $string; // internal only!!
final function getMessage() {
return $this->message;
}
final function getCode() {
return $this->code;
}
final function getFile() {
return $this->file;
}
?>
XML
После изменения объектной модели самым существенным инновациям (на мой взгляд) подверглась работа с XML. В PHP 4 поддержка данных технологий была довольно разнородной, если не сказать бестолковой. Для использования XSTL была необходима библиотека Sablotron, для SAX – Expat и, наконец, для полноценной работы с DOM – библиотека libxml2. Причём в последнем случае имели место многочисленные ошибки, утечки памяти и несоответствие API стандартам W3C (впрочем, это был наименее болезненный пункт).
С появлением PHP 5 всё радикально изменилось. Все вышеперечисленные расширения (и два новых, о которых речь пойдёт ниже) теперь основаны на libxml2, расширение DOM полностью соответствует стандартам и поддерживает три вида схем для проверки (валидации XML-документов: DTD, XML Schema и RelaxNG. SAX-расширение можно заставить работать под старой библиотекой Expat для совместимости со старыми приложениями, пересобрав PHP с соответствующей опцией, но в большинстве случаев такие ухищрения не понадобятся (как, собственно, и сам SAX, но это уже моё личное мнение).
Особенность работы с XSLT (также основанной на libxml2) теперь состоит в том, что XSL-преобразование не принимает таблицу стилей XSLT в качестве параметра, а зависит от расширения DOM. Таблица стилей теперь может кэшироваться в памяти и применяться ко многим документам без дополнительной загрузки.
В общем, подытоживая, можно сказать, что, совсем чуть потеряв, мы получили довольно много, а именно, наконец-то стабильно работающую реализацию DOM.
Теперь о новинках. Появились два новых XML-расширения – SampleXML и SOAP (Simple Object Access Protocol). Вообще-то каждое из них заслуживает отдельного разговора, но если быть кратким, то первое – это прозрачное представление XML-документа как родного объекта PHP. Что особенно ценно в случае невозможности (в силу ограничений данного расширения) выполнить какие-либо действия, всегда сохраняется шанс, преобразовать объект SampleXML в дерево DOM, выполнить необходимые действия и вернуться обратно, к SampleXML (функции dom_import_() и simplexml _import_dom () соответственно). Оба расширения реализованы в одной библиотеке, и переключения между ними теперь, по крайней мере, безболезненны.
Поддержка SOAP в PHP 4 осуществлялась при помощи соответствующего пакета из PEAR и была недостаточно полноценна. В PHP 5 реализация SOAP была полностью переписана, как С-расширение, и теперь практически соответствует стандарту.
Помню, несколько лет назад разворачивались довольно оживлённые дискуссии о самой возможности работать с веб-сервисами посредством PHP. С тех пор появилось несколько реализаций SOAP, таких как PEAR::SOAP (http://pear.php.net), NuSOAP (http://dietrich.ganx4.com/nusoap) и eZ SOAP (http://ez.no). Все они были написаны на PHP, и самым важным преимуществом нового расширения, по-видимому, следует считать скорость работы. Кроме того, в расширении SOAP почти полностью реализованы спецификации SOAP 1.1 и SOAP 1.2, в частности поддержка комплексных типов данных и SOAP-заголовков. А также WSDL 1.1, на котором хотелось бы остановиться особо.
Сама реализация SOAP в этом расширении диктует использовать WSDL (Web Services Description Language) там, где это возможно. Причём для увеличения скорости работы WSDL-файл кэшируется, и параметры кэширования настраиваются в конфигурационном файле php.ini.
Преимущества WSDL-стиля поясню на примере. Так выглядит простейший SOAP-клиент, написанный без применения WSDL:
$client = new SoapClient(null, array(
"location" => "http://localhost/soap.php",
"uri" => "http://test-uri/",
"style" => SOAP_DOCUMENT,
"use" => SOAP_LITERAL));
А так – тот же самый клиент, переписанный с использованием WSDL:
$client = new SoapClient("some.wsdl");
При вызове методов различий в реализации гораздо больше. Так как отпадает необходимость указания не только URI-сервера, но и пространства имен, заголовка SOAP Action, способа кодирования и типов параметров. Вся эта информация берется из WSDL-документа. Единственной проблемой остаётся получение клиентом WSDL-файла с сервера, но она решается за счёт вышеупомянутого механизма кэширования.
Тут, наверное, следует остановиться, поскольку это довольно большая и серьёзная тема и хоть как-нибудь развернуть её в нескольких абзацах не представляется возможным. Заинтересовавшихся отсылаю к статье Дмитрия Стогова, одного из авторов SOAP-расширения PHP, «Практическое использование SOAP в PHP 5» (http://www.zend.com/php5/articles/php5-SOAP.php).
Базы данных
Так уж сложилось, что наиболее «php-совместимым» сервером баз данных является СУБД MySQL. Эта связка была поставлена под угрозу зимой 2004 года, когда MySQL AB изменила лицензию своего продукта, основанного на GPL.
Если не вдаваться в юридические тонкости, можно просто сказать, что клиентская библиотека MySQL по умолчанию в PHP больше не присутствовала. Её, конечно, можно было установить, но предварительно тщательно ознакомившись с лицензией. Честно говоря, в среде PHP-программистов это известие вызвало некоторый шок (и это несмотря на то, что связка PHP 4.x и MySql 3.x оставалась вполне легитимной). Часть разработчиков устремилась в сторону PostgreSQL, а часть просто обратила внимание на появившееся уже в версии 4.3x новое расширение MySQLite.
Была ещё одна причина заинтересоваться этой библиотекой. Периодически на форумах разработчиков поднимается вопрос – можно ли написать веб-приложение, «управляемое данными», без использования сервера баз данных. Вообще мне всегда казалось, что эта экономия (ну, разумеется, на хостинге) совершенно неуместна, но вот встроенная библиотека SQLite, пожалуй, добавляет плюсов подобному подходу. Во всяком случае средство работы с данными (как бы удачней этот софт назвать?), поддерживающее такие возможности, как транзакции, вложенные запросы и представления, по крайней мере заслуживает интереса.
А что же с MySQL?
В общем, юридические проблемы благополучно разрешились. Товарищи из MySQL AB, похоже, опомнились, и теперь ограничения на клиентскую библиотеку снято (вообще понять их можно, популярность MySQL во многом была основана на широком распространении PHP). Более того, введено новое расширение, mysqli (Improved MySQL Extenrsion), поддерживающее новые возможности MySQL, появившиеся в версии 4.1 и выше, такие как транзакции, репликация и т. д. (правда, стоит оговориться, что многие из них ещё не реализованы).
Прочее
Автозагрузка
Как известно, работая с PHP, приходится мириться с тем фактом, что препроцессор не держит приложение в памяти целиком, а подгружает все файлы при обращении к каждой странице. При использовании какого-нибудь популярного движка совершенно очевидна избыточность получаемого кода, но настройка подключения только необходимых классов или файлов – довольно кропотливое и неблагодарное занятие. В PHP 5 эта проблема решена с помощью функции-события _autoload(). Суть её работы в следующем: при обращении к неизвестному классу или интерфейсу автоматически подгружается файл, содержащий их описание. Данная функция также снимает проблему включения файлов в порядке иерархии наследования. Надо сказать, что реализация автозагрузки на настоящий момент вызывает много нареканий, но останавливаться на них не буду, поскольку, скорее всего, к моменту выхода статьи большинство обнаруженных ошибок будут исправлены.
COM
Как известно, в PHP 4 (а точнее немного раньше) в языке появилась поддержка COM-технологии.
На практике это означало возможность работы с любыми объектами, имеющими COM-интерфейс, в том числе и с приложениями Microsoft Office (что особо ценно, когда твои отчёты требуются бухгалтерии или шефу).
Правда, данная реализация имела существенные неудобства, связанные с недостатками объектной модели РНР 4, которая накладывала ограничения и на сами скрипты, и на использование СОМ-расширений.
В пятой версии все, что связано с работой COM-расширений, было полностью переписано (причём такие, несколько несвойственные идеологии COM-модели функции, как com_addref(), com_release(), com_get(), com_set(), com_isenum() и com_load() попросту ликвидированы, что, строго говоря, порождает некоторые проблемы обратной совместимости). Добавлено много возможностей, из которых наиболее полезными (лично мне), представляются следующие:
- Обработка исключительных ситуаций (в PHP 4, внутри COM-кода это было невозможно). Она осуществляется с помощью класса com_exception, который является расширением базового класса обработки исключений exception, предоставляемого РНР, и включает все его методы.
- Для перебора теперь доступна функция foreach(), тем, кто имел опыт работы с COM посредством PHP, поймут всё удобство этого новшества.
- Тип variant, наконец, обрёл нормальный, работоспособный вид, впрочем, об этом тоже можно довольно много говорить.
- Модель OO в PHP 5 позволяет РНР-препроцессору самостоятельно получать от COM-объекта информацию о методе, который будет вызван.
.Net
В РНР 5 встроена поддержка .Net. Точнее, есть возможность работать с экземплярами объектов, определенных в .Net через взаимодействия с COM-оберткой.
То есть можно считать, что PHP «видит» объекты .Net так, как если бы они были объектами COM, что даёт разработчику доступ к библиотеке .Net-классов.
Standard PHP Library (SPL)
SPL, по сути, является средством расширяемости Zend Engine, это альтернативное расширение для Zend Engine 2, которое определяет стандартный набор интерфейсов. Ваш объект использует интерфейс из SPL, и, когда осуществляется доступ к объекту через встроенные конструкции PHP, вызываются различные методы, определённые интерфейсом. Данная возможность основана на новых внутренних свойствах Zend Engine 2, позволяющих создавать собственные и перезаписывать существующие машинные коды (то есть opcodes – наборы инструкций, в которые компилируется PHP-скрипт). На мой взгляд, SPL – самая спорная по полезности возможность PHP 5, так как сильно затрудняет работу с вашим кодом других разработчиков.
Новый API потоков
Понятие потоков (streams) появилось в PHP, начиная с версии 4.3.0. Этот механизм дал возможность абстрагированно работать с файлами, сетевыми ресурсами и архивами, предоставляя единый интерфейс доступа. В пятой версии препроцессора возможности работы с потоками значительно расширены, в частности, доступны низкоуровневые операции с сокетами, работа с сокет-сервером. Пример работы с сокетами из документации:
<?php
$socket = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr);
if (!$socket) {
echo "$errstr ($errno)<br />\n";
} else {
while ($conn = stream_socket_accept($socket)) {
fwrite($conn, 'The local time is ' . date('n/j/Y g:i ї
a') . "\n");
fclose($conn);
}
fclose($socket);
}
?>
Честно говоря, такие возможности мне лично использовать не приходилось, но само их наличие впечатляет.
Perl
Благодаря новому расширению для работы с Perl (не включённому по умолчанию), в PHP 5 теперь возможно прямо из PHP-кода вызывать Perl-скрипты и работать с объектами Perl.
Tidy
В PHP 5 включена поддержка библиотеки Tidy (http://tidy.sf.net), позволяющей разработчикам разбирать, проверять синтаксис и восстанавливать документы HTML. Используется как функциональный, так и объектно-ориентированный интерфейс, а также механизм исключений РНР 5.
Уровень сообщений об ошибках
Новый уровень сообщений об ошибках E_STRICT включает вывод сообщений об использовании в коде устаревших (с точки зрения PHP 5) методов программирования. Он не входит в уровень E_ALL, поэтому рекомендуемый уровень выглядит так: E_ALL | E_STRICT.
Новый менеджер памяти
Главными преимуществами менеджера памяти Zend Engine II являются улучшенная поддержка многопоточных сред и гораздо более эффективное освобождение распределённых блоков памяти после каждого запроса.
С полным списком нововведений можно ознакомиться на сайте компании Zend Technologies, по адресу http://www.zend.com/php5/whats-new.php.
Ложка дёгтя
При выходе любой новой версии, того или иного продукта, неизбежно возникает проблема обратной совместимости. Сразу встаёт вопрос разумной грани между полной обратной совместимостью и добавлением новых, где-то даже революционных возможностей. Мне кажется, что разработчики PHP благополучно преодолели эти грабли, впрочем, судите сами.
Во-первых, данные проблемы будут касаться программ, опирающихся на старые механизмы реализации классов. Выхода тут два: переписать код, используя вышеупомянутый метод __clone(), или в конфигурационном файле php.ini включить параметр ze2.implicit_clone, приказав объектам вести себя по привычной для PHP 4 схеме, вместе с тем оставляя возможность использовать свойства PHP 5, такие как унифицированные конструкторы, пространства имён, исключения, и т. д.
Правда, последнее больше похоже на капитуляцию, но при наличии уже существующих достаточно объёмных и сложных проектов этот выход довольно разумен.
При работе с объектами необходимо также учитывать то обстоятельство, что свойства объекта должны быть предопределены, то есть нижеприведённый код работать не будет:
<?php
class Container {
}
$c = &new Container;
$c->name = "Sterling";
echo $c->name;
?>
Следующая по значимости проблема связана с новыми правилами работы с XML, дело тут не в изменении используемых библиотек, а в том, что названия функций API были приведены в соответствие со стандартами W3C. Шаг болезненный но, по-видимому, необходимый. Для разработчика нет другого пути, как переименовать функции в старой программе (благо с точки зрения функциональности ничего не изменилось).
Что ещё?
Теперь зарезервированными являются следующие слова: try, catch, throw, exception, public, private, protected, abstract, interface, final.
Кроме того, при объявлении класса к ним добавляются __call, __get, __set, __clone, __construct, __destruct. Правда, я с трудом представляю программиста, который использует подобные имена для констант или переменных, но тем не менее.
И наконец, самая фатальная потеря. Больше не поддерживается операционная система Windows 95. Не поддерживается, потому что не способна (по заявлению разработчиков) реализовать новые возможности языка. Мне кажется, что это известие поселит траур в душах большинства PHP-программистов.
Резюме
С моей точки зрения, вопрос, обновлять или не обновлять PHP, не стоит. Практически ничего не теряя, мы обретаем впечатляющие новые возможности. Другой вопрос в том, что эти самые возможности диктуют по крайней мере несколько иной стиль программирования. Разумеется, многие преимущества пятой версии можно использовать и без этого, но, несмотря на заявления основателей Zend и самого Расмуса Лердорфа, очевидно, что идеология языка существенно изменилась.
Мне кажется, что это ни хорошо и ни плохо, это просто было неизбежно.
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|