Zend Framework では、クライアントとしてリモートの
XML-RPC サービスを使用することもサポートしています。そのためには
Zend_XmlRpc_Client パッケージを使用します。
主な機能には、PHP と XML-RPC の間の型変換やサーバのプロキシオブジェクト、
そしてサーバが提供する機能を調べることなどがあります。
Zend_XmlRpc_Client のコンストラクタは、
リモート XML-RPC サーバの URL を最初の引数として受け取ります。
返されたインスタンスを使用して、
その場所からさまざまなリモートメソッドを実行します。
リモートメソッドを XML-RPC クライアントからコールするには、
インスタンスを作成した後で call() メソッドをコールします。
以下の例では Zend Framework のウェブサイト上にあるデモ用の
XML-RPC サーバを使用します。Zend_XmlRpc
のテストや調査のために、このサーバを使用することができます。
例 36.1. XML-RPC メソッドのコール
<?php
require_once 'Zend/XmlRpc/Client.php';
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
echo $client->call('test.sayHello');
// hello
?>
リモートメソッドのコールによって返される XML-RPC の値は、
自動的に PHP のネイティブ型に変換されます。
上の例では PHP の string が返されるので、
それをそのまま使用することができます。
call() メソッドの最初のパラメータは、
コールするリモートメソッドの名前です。
そのリモートメソッドが何らかのパラメータを要求する場合は、それを
call() の二番目のオプションのパラメータで指定します。
このパラメータには、リモートメソッドに渡す値を配列で指定します。
例 36.2. パラメータを指定した XML-RPC メソッドのコール
<?php
require_once 'Zend/XmlRpc/Client.php';
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
$arg1 = 1.1;
$arg2 = 'foo';
$result = $client->call('test.sayHello', array($arg1, $arg2));
// $result はネイティブな PHP の型になります
?>
リモートメソッドがパラメータを要求していない場合は、
このパラメータには何も指定しません。あるいは空の array()
を渡します。リモートメソッドに渡すパラメータの配列には、
ネイティブの PHP 型と Zend_XmlRpc_Value
オブジェクトの両方を使用できます。それらを混用することも可能です。
call() メソッドは自動的に XML-RPC のレスポンスを変換し、
同等な PHP ネイティブ型にして返します。返り値を
Zend_XmlRpc_Response オブジェクトとして取得するには、
このメソッドの後で getLastResponse() をコールします。
リモートメソッドの中にはパラメータが必要なものがあります。
必要なパラメータは、Zend_XmlRpc_Client の
call() メソッドの二番目のパラメータとして配列で指定します。
パラメータを渡す方法は 2 通りあります。PHP のネイティブ型
(これは自動的に変換されます) で渡すか、
対応する XML-RPC 型 (Zend_XmlRpc_Value
オブジェクトのひとつ) で渡すかのいずれかです。
call() のパラメータをネイティブの PHP
型で渡します。つまり string、
integer、float、
boolean、array あるいは
object で渡すということです。
このとき、PHP のネイティブ型は自動的に検出され、
以下の表にしたがって XML-RPC 型に変換されます。
パラメータを表す Zend_XmlRpc_Value
のインスタンスを作成し、XML-RPC の型を指定することもできます。
このようにする理由には次のようなものがあります。
プロシージャに正しい型で渡されることを確実にしたいことがある (例えば、integer を要求しているプロシージャに対して データベースから取得した文字列を渡したい場合など)。
プロシージャが base64 型や
dateTime.iso8601 型を要求していることがある
(これらは PHP のネイティブ型には存在しません)。
自動変換が失敗する場合 (例えば、空の XML-RPC 構造体をパラメータとして渡すことを考えましょう。 これは、PHP では空の配列に対応します。しかし、 空の配列をパラメータとして渡すと、それが自動変換されたときに XML-RPC の array になってしまいます。なぜなら、 空の配列は連想配列ではないからです)。
Zend_XmlRpc_Value オブジェクトを作成する方法は
二通りあります。Zend_XmlRpc_Value
のサブクラスのインスタンスを直接作成するか、
あるいは静的ファクトリメソッド Zend_XmlRpc_Value::getXmlRpcValue()
を使用します。
表 36.2. Zend_XmlRpc_Value オブジェクトと対応する XML-RPC 型
| XML-RPC 型 | 対応する Zend_XmlRpc_Value 定数 |
Zend_XmlRpc_Value オブジェクト |
|---|---|---|
| int | Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER |
Zend_XmlRpc_Value_Integer |
| double | Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE |
Zend_XmlRpc_Value_Double |
| boolean | Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN |
Zend_XmlRpc_Value_Boolean |
| string | Zend_XmlRpc_Value::XMLRPC_TYPE_STRING |
Zend_XmlRpc_Value_String |
| base64 | Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64 |
Zend_XmlRpc_Value_Base64 |
| dateTime.iso8601 | Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME |
Zend_XmlRpc_Value_DateTime |
| array | Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY |
Zend_XmlRpc_Value_Array |
| struct | Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT |
Zend_XmlRpc_Value_Struct |
![]() |
自動変換 |
|---|---|
新しい |
リモートメソッドを XML-RPC クライアントからコールするもうひとつの方法は、 サーバプロキシを使用することです。 サーバプロキシとはリモートの XML-RPC 名前空間のプロキシとなる PHP オブジェクトで、ネイティブな PHP オブジェクトと可能な限り同じように扱えるようにしたものです。
サーバプロキシのインスタンスを作成するには、
Zend_XmlRpc_Client のインスタンスメソッド
getProxy() をコールします。これは
Zend_XmlRpc_Client_ServerProxy のインスタンスを返します。
サーバプロキシに対するあらゆるメソッドコールはリモートに転送され、
パラメータも通常の PHP メソッドと同じように渡すことができます。
例 36.3. デフォルト名前空間のプロキシ
<?php
require_once 'Zend/XmlRpc/Client.php';
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
$server = $client->getProxy(); // デフォルトの名前空間のプロキシを作成します
$hello = $server->test->sayHello(1, 2); // test.Hello(1, 2) は "hello" を返します
?>
getProxy() のオプションの引数で、
リモートサーバのどの名前空間をプロキシするかを指定することができます。
名前空間を指定しなかった場合は、デフォルトの名前空間をプロキシします。
次の例では、test 名前空間がプロキシの対象となります。
例 36.4. 任意の名前空間のプロキシ
<?php
require_once 'Zend/XmlRpc/Client.php';
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
$test = $client->getProxy('test'); // "test" 名前空間のプロキシを作成します
$hello = $test->sayHello(1, 2); // test.Hello(1,2) は "hello" を返します
?>
リモートサーバが入れ子状の名前空間をサポートしている場合は、
サーバプロキシでもそれを使用することができます。たとえば、
上の例のサーバがメソッド test.foo.bar()
を保持している場合は、$test->foo->bar()
のようにコールします。
XML-RPC のメソッドコールで発生する可能性のあるエラーには、二種類あります。
HTTP のエラーと XML-RPC の fault です。Zend_XmlRpc_Client
はこれらの両方を理解するので、それぞれ独立して検出と処理が可能です。
HTTP エラーが発生した場合、
つまり、たとえばリモート HTTP サーバが
404 Not Found を返したような場合に
Zend_XmlRpc_Client_HttpException がスローされます。
例 36.5. HTTP エラーの処理
<?php
require_once 'Zend/XmlRpc/Client.php';
$client = new Zend_XmlRpc_Client('http://foo/404');
try {
$client->call('bar', array($arg1, $arg2));
} catch (Zend_XmlRpc_HttpException $e) {
// $e->getCode() は 404 を返します
// $e->getMessage() は "Not Found" を返します
}
?>
XML-RPC クライアントの使用法にかかわらず、HTTP エラーが発生すると必ず
Zend_XmlRpc_Client_HttpException がスローされます。
XML-RPC の fault は、PHP の例外と似たものです。これは
XML-RPC メソッドのコールから返される特別な型で、
エラーコードとエラーメッセージを含みます。XML-RPC の fault
は、Zend_XmlRpc_Client の使用場面によって処理方法が異なります。
call() メソッドや
サーバプロキシオブジェクトを使用している場合には、
XML-RPC の fault が発生すると
Zend_XmlRpc_Client_FaultException がスローされます。
この例外のコードとメッセージは、もとの XML-RPC の fault
レスポンスの値に対応するものとなります。
例 36.6. XML-RPC Fault の処理
<?php
require_once 'Zend/XmlRpc/Client.php';
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
try {
$client->call('badMethod');
} catch (Zend_XmlRpc_FaultException $e) {
// $e->getCode() は 1 を返します
// $e->getMessage() は "Unknown method" を返します
}
?>
call() メソッドを使用してリクエストを作成した場合は、
fault の際に Zend_XmlRpc_FaultException
がスローされます。fault を含む Zend_XmlRpc_Response
オブジェクトを取得するには
getLastResponse() をコールします。
doRequest() メソッドでリクエストを作成した場合は、
例外はスローされません。そのかわりに、falut を含む
Zend_XmlRpc_Response オブジェクトを返します。
これを調べるには、
Zend_XmlRpc_Response のインスタンスメソッド
isFault() を使用します。
XML-RPC サーバの中には、XML-RPC の system. 名前空間で
デファクトのイントロスペクションメソッドをサポートしているものもあります。
Zend_XmlRpc_Client は、この機能を持つサーバもサポートしています。
Zend_XmlRpcClient の getIntrospector() メソッドをコールすると、
Zend_XmlRpc_Client_ServerIntrospection のインスタンスを取得できます。
これを使用してサーバのイントロスペクションを行います。
Zend_XmlRpc_Client のインスタンスメソッド call() 中で行われていることは、
まずリクエストオブジェクト (Zend_XmlRpc_Request) を作成し、
それを別のメソッド doRequest() で送信し、
その結果返されるレスポンスオブジェクト (Zend_XmlRpc_Response)
を取得するということです。
doRequest() メソッドは、それ単体で直接使用することもできます。
例 36.7. リクエストからレスポンスへの処理
<?php
require_once 'Zend/XmlRpc/Client.php';
$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
$request = new Zend_XmlRpc_Request();
$request->setMethod('test.sayHello');
$request->setParams(array('foo', 'bar'));
$client->doRequest($request);
// $server->getLastRequest() は Zend_XmlRpc_Request のインスタンスを返します
// $server->getLastResponse() は Zend_XmlRpc_Response のインスタンスを返します
?>
クライアントから XML-RPC メソッドのコールが
(call() メソッド、
doRequest() メソッドあるいはサーバプロキシによって)
行われた場合は、最後のリクエストオブジェクトおよびその応答が常に
getLastRequest() および
getLastResponse() で取得できます。
これまでのすべての例では、HTTP クライアントの設定を行いませんでした。
このような場合、Zend_Http_Client
の新しいインスタンスがデフォルトのオプションで作成され、それを自動的に
Zend_XmlRpc_Client で使用します。
HTTP クライアントは、いつでも
getHttpClient() メソッドで取得できます。
たいていの場合はデフォルトの HTTP クライアントで用が足りるでしょう。
しかし、setHttpClient() を使用することで、
別の HTTP クライアントのインスタンスを使うこともできます。
setHttpClient() は、特に単体テストの際に有用です。
Zend_Http_Client_Adapter_Test と組み合わせることで、
テスト用のリモートサービスのモックを作成することができます。
この方法を調べるには、Zend_XmlRpc_Client
自体の単体テストを参照ください。