Com_dotnet
COM и PHP.
Wez Furlong
16-03-2004
Перевод статьи Вадим Крючков aka Long.
Оригинал находится по адресу http://www.zend.com/php5/articles/php5-dotnet.php
Введение
Нововведения в объектно-ориентированном (ОО) подходе PHP 5 не ограничиваются введением приватных (private), защищенных (protected) и публичных (public) переменных в ваших скриптах, позволяющие полноценно интегрировать поддержку внешних объектных моделей таких как COM, Java, .Net и Corba. Но это стало превосходной возможностью действительно оживить поддержку COM, которая, из-за ограничений объектной модели РНР 4, накладывала ограничения и на сами скрипты, и на использование СОМ-расширений. Для этого была полностью переписана поддержка СОМ и даже убрана обратная совместимость с наиболее неестественными аспектами СОМ-расширений РНР 4.
Более не поддерживается
Следующие функции и возможности более не поддерживаются в работе с COM в PHP 5, так как они, вообще говоря, плохо согласуются с самой идеей COM, и больше сбивают с толку, если вы посмотрите их описание в документации.
com_addref(), com_release() – скрипт может больше не заботится о счетчике ссылок
com_get(), com_set(), com_invoke(),com_propget(), com_propset(), com_propput() – логичнее использовать обычный ОО синтаксис РНР для получения или установки свойств или вызова методов объекта.
com_isenum() и $com->Next() – теперь используйте вместо этого синтаксис foreach(), описанный ниже.
com_load() – вместо этого используйте оператор new и встроенный класс СОМ.
Итак, весь этот хлам будет уничтожен. А теперь посмотрим, какие "вкусности" будут добавлены.
Iterators 1
Если вы когда-либо имели дело с VBscript, например, при написании ASP сайтов или административных vbs-скриптов, вы непременно видели подобный код:
<%
set domainObject = GetObject("WinNT://Domain")
for each obj in domainObject
Response.write obj.Name & "<br>"
next
%>
В СОМ для PHP 4, эквивалентный код выглядит так:
<?php
$domainObject = new COM("WinNT://Domain");
while ($obj = $domainObject->Next()) {
echo $obj->Name . "<br>";
}
?>
Если вы подробно изучали VB/COM, взглянув на этот пример, вас должно удивить, что именно Next() производит перебор, так как это не реально существующий метод класса, и вы ни за что не найдете его в других языках, поддерживающих СОМ. В РНР 5 такой синтаксис был упразднен за счет более подходящего для этих целей оператора foreach():
<?php
$domainObject = new COM("WinNT://Domain");
foreach ($domainObject as $obj) {
echo $obj->Name . "<br>";
}
?>
Обработка исключений
В РНР 4 не было нормальных возможностей для реализации обработчика ошибок, срабатывающего в пределах СОМ-кода при возникновении ошибки. РНР позволял устанавливать E_WARNING, для того чтобы узнать, что случилась ошибка, но вы не имели возможности узнать точно - в какой момент и при каких условиях случилась ошибка, чтобы программно ее обработать.
В PHP 5 вводится новая конструкция, позволяющая обработать исключительные ситуации (try, catch() и throw()), которая позволяет обрабатывать исключения, используя встроенный в РНР класс com_exception. Если Вы хотите отловить ошибки в ваших скриптах, вы могли бы написать примерно такой код:
<?php
$com = new COM("...");
try {
$com->call_a_method();
}
catch (com_exception $e) {
print $e . "\n";
}
?>
Внутри блока catch вы можете обрабатывать ошибку наиболее подходящим вашей программе способом. Класс com_exception является расширением базового класса обработки исключений exception, предоставляемого РНР, и включает все его методы. Код ошибки доступен через метод getCode() класса, делая легким обработку специфических ошибок.
Тип Variant
Одной из не очень хорошо задокументированных особенностей СОМ в РНР 4 является поддержка типа данных VARIANT. Если вы не знакомы с этим типом данных, то можете представлять его, как некий эквивалент переменной РНР, которая может содержать данные различных типов (целые, переменные с плавающей точкой, строковые или объекты). Тип variant, использующийся в СОМ, более разнообразен, чем просто РНР переменные, и не всегда может быть приведен к "родным" типам РНР. Поддержка типа variant в РНР 4 такова, что зависит от направления преобразования между СОМ и РНР, и в результате мы имели кошмарный код обработки преобразований типов данных. К тому же, это было чревато множеством ошибок и не позволяло обрабатывать все возможные случаи преобразования. Не исключена была даже возможность, что при преобразовании вы могли потерять данные или их точность.
В PHP 5 работа с variant сильно упрощена. Теперь преобразование типов исходит из предпосылки, что нужно преобразовывать переменную типа variant к "родному" типу PHP, только когда есть возможность прямого, один-к-одному преобразования. Во всех остальных случаях, мы представляем тип variant как перегруженный объект, и откладываем выбор конечного типа до момента пока он не будет использоваться в выражении. Как следствие, мы имеем намного понятный и чистый код и, если вы работаете с массивами, элементы которых имеют тип variant, намного быстрее работающие скрипты, поскольку мы больше не должны копировать содержимое исходного массива в массив PHP - новая модель OO в PHP 5 позволяет нам получать доступ к объекту variant, как если бы это был обычный массив.
Другой приятный момент, ставший возможным благодаря новой модели OO - интеллектуальная интерпретация содержимого объекта variant, используя обработчик приведения типов. Как я говорил выше, мы откладываем выбор конечного типа, пока объект не будет использован в выражении. В момент подстановки, Zend Engine рассматривает в каком контексте используется объект (числовой, строковый и т.д.) и преобразует объект к соответствующему типу. Такой подход позволяет точно конвертировать переменную.
Если этого не достаточно, существует большое количество различных API-функций COM, которые позволяют вам суммировать, вычитать, умножать и производить иные действия с типом variant согласно таким же правилам, которые используются в VB. С одной стороны, такая возможность для базовых типов (целые числа и строки) не кажется полезной , но оказывается крайне это полезной и необходимой для "экзотических" типов (даты, валюты и других).
Передача параметров по ссылке (ByRef)
Обычной ситуацией при работе с СОМ объектами является передача параметров по ссылке. В PHP 4, единственной возможностью передать тип variant по ссылке, было вручную создать экземпляр variant и передать его как ссылку. Модель OO в PHP 5 позволяет РНР движку самостоятельно получать от COM-объекта информацию о методе, который будет вызван, чтобы определить, какие параметры необходимо передать по ссылке. Это позволяет вам вызывать СОМ-методы, не заботясь о методе передачи переменных - нужный метод будет установлен автоматически.
Управление событиями
Строго говоря, это не является нововведением для PHP 5 (и было добавлено еще это в PHP 4.3), но об этом стоит упомянуть здесь, так как такая возможность не была хорошо задокументирована. Весьма часто вы должны связать с СОМ объектом определенное событие. В VB, для этих целей используется оператор WithEvents при определении переменной, и Visual Basic будет вызывать метод автоматически. В РНР есть небольшие отличия, но при этом подход более последователен.
Чтобы обрабатывать события от COM объекта-источник, вы должны создать объект, который будет получать эти события. Для этого вы просто определяете свой класс-приемник сообщений, создаете экземпляр этого класса, а затем связываете события с ним:
<?php
// класс-приемник сообщений
class IESink {
var $terminated = false;
function OnQuit() { $this->terminated = true; }
}
// создаем экземпляр класса IESink
$sink = new IESink;
// создаем экземпляр СОМ, связанный с IE
$ie = new COM("InternetExplorer.Application");
// связываем события СОМ-объекта с нашим обработчиком
com_event_sink($ie, $sink, "DWebBrowserEvents2");
$ie->Visible = true; // отображаем IE
$ie->Navigate("http://www.php.net/"); // загружаем страницу http://www.php.net
// ожидаем закрытия браузера
while (!$sink->terminated) {
com_message_pump(4000);
}
?>
Этот скрипт запускает Interne Explorer и загружает домашную страницу PHP (http://www.php.net/) и будет ожидать закрытия браузера для продолжения. Нужно отметить, что com_event_sink () функция отвечает за установку пересылки событий от $ie к $sink, и что используется интерфейс "DWebBrowserEvents2". Название интерфейса должно точно соответствовать названию так называемого внешнего диспетчерского интерфейса (интерфейс, который осуществляет доступ к сервисам COM-объектов) для вашего COM объекта. Вы можете узнать название и также сгенерировать шаблон класса-приемника, используя функцию com_print_typeinfo().
Поддержка .Net
В РНР 5 встроена поддержка .Net. Если быть более точным, поддерживается экземпляр объектов, определенных в .Net-сборках через взаимодействия с COM-оберткой. Т.е. можно считать, что PHP "видит" объекты .Net так, как если бы они были объектами COM, хотя экземпляры объектов немного отличаются:
<?php
$stack = new DOTNET("mscorlib", "System.Collections.Stack");
$stack->Push(".Net");
$stack->Push("Hello ");
echo $stack->Pop() . $stack->Pop();
?>
Таким образом, РНР 5 предоставляет Вам удобный доступ к очень обширной библиотеке .Net классов (которая насчитывает несколько тысяч различных классов!). Разумеется, чтобы использовать эти возможности вы должны установить .Net RunTime на ваш сервер.
Заключение
Хотя каждая возможность, которую я упомянул выше, по отдельности не столь значима, общий эффект от нового подхода можно ощутить, если вы когда-либо писали скрипты используя возможности СОМ. Вы обнаружите, что скрипт стал не только много короче, легко читаемым и понимаемым, но стал и быстрее выполняться.
Вы можете попробовать все эти возможности прямо сейчас, загрузив снапшот PHP 5 (http://snaps.php.net). В настоящее время PHP 5 находится в стадии стабилизации кода, готовится первый стабильный релиз. Текущая версия (на момент перевода Release Candidate 2) уже довольно стабильна, так что вы можете приступать непосредственно к полевым испытаниям. Если Вы сталкиваетесь с проблемами, пожалуйста, сообщите о них по адресу http:// bugs.php.net.
Об авторе
Wez Furlong - разработчик ядра PHP и "главный" по PECL (The PHP Extension Community Library), содействовавший разработкам расширений, таких как SQLite, COM/.Net, ActivePHP, mailparse, Streams API и другим.
1 iterator - управляющая структура, определяющая порядок выполнения некоторых повторяющихся действий, устройство или программа организации циклов.






967-043