<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<!-- EN-Revision: 24249 -->
<sect1 id="zend.http.client.adapters">
    <title>Zend_Http_Client - 接続アダプタ</title>

    <sect2 id="zend.http.client.adapters.overview">
        <title>概要</title>

        <para>
            <classname>Zend_Http_Client</classname> は、接続アダプタとして設計されています。
            接続アダプタは実際にサーバへの接続を行うオブジェクトで、
            リクエストの書き込みやレスポンスの読み込みも行います。
            この接続アダプタは置き換えることができます。
            つまり、デフォルトの接続アダプタを継承して自分の好みにあうように変更できます。
            <acronym>HTTP</acronym> クライアントクラス全体を書き換える必要はありません。
            同じインターフェイスを実装しているだけでいいのです。
        </para>

        <para>
            現在、<classname>Zend_Http_Client</classname> クラスは四つの組み込み接続アダプタを提供しています。
            <itemizedlist>
                <listitem>
                    <para>
                        <classname>Zend_Http_Client_Adapter_Socket</classname> (デフォルト)
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <classname>Zend_Http_Client_Adapter_Proxy</classname>
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <classname>Zend_Http_Client_Adapter_Curl</classname>
                    </para>
                </listitem>

                <listitem>
                    <para>
                        <classname>Zend_Http_Client_Adapter_Test</classname>
                    </para>
                </listitem>
            </itemizedlist>
        </para>

        <para>
            <classname>Zend_Http_Client</classname> オブジェクトの接続アダプタを指定するには、
            設定オプション 'adapter' を使用します。
            クライアントオブジェクトのインスタンスを作成する際に、オプション
            'adapter' にアダプタの名前 (たとえば 'Zend_Http_Client_Adapter_Socket' など)
            を指定できます。あるいは、アダプタオブジェクトの変数
            (たとえば <command>new Zend_Http_Client_Adapter_Test</command> など) を指定することもできます。
            <classname>Zend_Http_Client->setConfig()</classname> メソッドを使用し、
            アダプタを後で設定することも可能です。
        </para>
    </sect2>

    <sect2 id="zend.http.client.adapters.socket">
        <title>ソケットアダプタ</title>

        <para>
            デフォルトの接続アダプタは <classname>Zend_Http_Client_Adapter_Socket</classname>
            です。明示的に接続アダプタを指定しない場合は、これが使用されます。
            Socket アダプタは <acronym>PHP</acronym> の組み込み関数 fsockopen()
            を使用しており、特別な拡張モジュールやコンパイルオプションは必要ありません。
        </para>

        <para>
            ソケットアダプタには、追加の設定オプションを指定できます。これは
            <classname>Zend_Http_Client->setConfig()</classname> で指定するか、
            あるいはクライアントのコンストラクタに渡します。

            <table id="zend.http.client.adapter.socket.configuration.table">
                <title>Zend_Http_Client_Adapter_Socket の設定パラメータ</title>

                <tgroup cols="4">
                    <thead>
                        <row>
                            <entry>パラメータ</entry>
                            <entry>説明</entry>
                            <entry>予期する型</entry>
                            <entry>デフォルト値</entry>
                        </row>
                    </thead>

                    <tbody>
                        <row>
                            <entry>persistent</entry>

                            <entry>
                                持続的な <acronym>TCP</acronym> 接続を使用するかどうか
                            </entry>

                            <entry>boolean</entry>
                            <entry><constant>FALSE</constant></entry>
                        </row>

                        <row>
                            <entry>ssltransport</entry>
                            <entry><acronym>SSL</acronym> トランスポート層 (たとえば 'sslv2'、'tls')</entry>
                            <entry>文字列</entry>
                            <entry>ssl</entry>
                        </row>

                        <row>
                            <entry>sslcert</entry>

                            <entry>
                                <acronym>PEM</acronym> でエンコードした、<acronym>SSL</acronym> 証明書ファイルへのパス
                            </entry>

                            <entry>文字列</entry>
                            <entry><constant>NULL</constant></entry>
                        </row>

                        <row>
                            <entry>sslpassphrase</entry>

                            <entry>
                                <acronym>SSL</acronym> 証明書ファイルのパスフレーズ
                            </entry>

                            <entry>文字列</entry>
                            <entry><constant>NULL</constant></entry>
                        </row>

                        <row>
                            <entry>sslusecontext</entry>

                            <entry>
                                プロキシ接続そのものが行わないとしても、
                                プロキシされた接続でSSLを使用できるようにします。
                            </entry>

                            <entry>boolean</entry>
                            <entry><constant>FALSE</constant></entry>
                        </row>
                    </tbody>
                </tgroup>
            </table>

            <note>
                <title>持続的な TCP 接続</title>

                <para>
                    持続的な <acronym>TCP</acronym> 接続を使用すると、<acronym>HTTP</acronym>
                    リクエストの処理速度が向上する可能性があります。
                    しかし、たいていの場合はその効果はごくわずかで、
                    接続先の <acronym>HTTP</acronym> サーバにかかる負荷が大きくなります。
                </para>

                <para>
                    持続的な <acronym>TCP</acronym> 接続を使用するのは、
                    同じサーバに頻繁に接続する場合で
                    そのサーバが同時に多数の接続を処理できることがわかっている場合のみにすることを推奨します。
                    いずれにせよ、このオプションを使用する前には
                    クライアント側の速度だけでなくサーバ側の負荷についてもベンチマークをとるようにしましょう。
                </para>

                <para>
                    さらに、持続的な接続を使用するときには
                    <link linkend="zend.http.client.configuration">構成セクション</link>
                    で説明した Keep-Alive <acronym>HTTP</acronym> リクエストも有効にしておくことを推奨します。
                    そうしないと、持続的な接続の効果はほとんどといっていいほどなくなってしまいます。
                </para>
            </note>

            <note>
                <title>HTTPS SSL ストリームパラメータ</title>

                <para>
                    <property>ssltransport</property>, <property>sslcert</property> および <property>sslpassphrase</property>
                    は、<acronym>HTTPS</acronym> 接続で使用する <acronym>SSL</acronym> レイヤーにのみ関連するものです。
                </para>

                <para>
                    たいていの場合はデフォルトの <acronym>SSL</acronym> 設定でうまく動作するでしょうが、
                    接続先のサーバが特別なクライアント設定を要求している場合は
                    それにあわせた設定をする必要があるかもしれません。
                    その場合は、
                    <ulink
                        url="http://www.php.net/manual/ja/transports.php#transports.inet">ここ</ulink>
                    で <acronym>SSL</acronym> トランスポート層やオプションについての説明を参照ください。
                </para>
            </note>
        </para>

        <example id="zend.http.client.adapters.socket.example-1">
            <title>HTTPS トランスポート層の変更</title>

            <programlisting language="php"><![CDATA[
// 設定パラメータを指定します
$config = array(
    'adapter'      => 'Zend_Http_Client_Adapter_Socket',
    'ssltransport' => 'tls'
);

// クライアントオブジェクトのインスタンスを作成します
$client = new Zend_Http_Client('https://www.example.com', $config);

// これ以降のリクエストは、TLS セキュア接続上で行われます
$response = $client->request();
]]></programlisting>
        </example>

        <para>
            上の例の結果は、次の <acronym>PHP</acronym> コマンドで <acronym>TCP</acronym>
            接続をオープンした場合と同じになります。
        </para>

        <para>
            <methodname>fsockopen('tls://www.example.com', 443)</methodname>
        </para>

        <sect3 id="zend.http.client.adapters.socket.streamcontext">
            <title>ソケットアダプタのストリームコンテキストへのアクセスとカスタマイズ</title>

            <para>
                Zend Framework 1.9 以降、<classname>Zend_Http_Client_Adapter_Socket</classname>
                は、リモートサーバへの接続に使用している <ulink
                    url="http://www.php.net/manual/ja/stream.contexts.php">ストリームコンテキスト</ulink>
                に直接アクセスできるようになります。これを使用すると、
                <acronym>TCP</acronym> ストリーム (<acronym>HTTPS</acronym> 接続の場合は <acronym>SSL</acronym> ラッパー)
                固有のオプションやパラメータを渡せるようになります。
            </para>

            <para>
                ストリームコンテキストにアクセスするには、
                <classname>Zend_Http_Client_Adapter_Socket</classname>
                のこれらのメソッドを使用します。

                <itemizedlist>
                    <listitem>
                        <para>
                            <firstterm><methodname>setStreamContext($context)</methodname></firstterm>
                            アダプタが使用するストリームコンテキストを設定します。
                            <acronym>PHP</acronym> の <ulink
                                url="http://php.net/manual/ja/function.stream-context-create.php"><methodname>stream_context_create()</methodname></ulink>
                            関数で作成したストリームコンテキストリソースか、
                            この関数に渡すのと同じ形式のストリームコンテキストオプションの配列のいずれかを指定できます。
                            配列を渡すと、そのオプションを用いて新たなストリームコンテキストを作成し、
                            それを設定します。
                        </para>
                    </listitem>

                    <listitem>
                        <para>
                            <firstterm><methodname>getStreamContext()</methodname></firstterm>
                            アダプタのストリームコンテキストを取得します。
                            ストリームコンテキストが設定されていない場合は、
                            デフォルトのストリームコンテキストを作成してそれを返します。
                            あとは、さまざまなコンテキストオプションの設定や取得を通常の
                            <acronym>PHP</acronym> ストリームコンテキスト関数で行うことができます。
                        </para>
                    </listitem>
                </itemizedlist>
            </para>

            <example id="zend.http.client.adapters.socket.streamcontext.example-1">
                <title>ソケットアダプタのストリームコンテキストオプションの設定</title>

                <programlisting language="php"><![CDATA[
// オプションの配列
$options = array(
    'socket' => array(
        // ソケットのローカル側を特定のインターフェイスにバインドします
        'bindto' => '10.1.2.3:50505'
    ),
    'ssl' => array(
        // サーバ側の証明書を検証します
        // 無効な証明書や自己署名の SSL 証明書は拒否します
        'verify_peer' => true,
        'allow_self_signed' => false,

        // ピア証明書を捕捉します
        'capture_peer_cert' => true
    )
);

// アダプタオブジェクトを作成し、HTTP クライアントにバインドします
$adapter = new Zend_Http_Client_Adapter_Socket();
$client = new Zend_Http_Client();
$client->setAdapter($adapter);

// 方法 1: オプションの配列を setStreamContext() に渡します
$adapter->setStreamContext($options);

// 方法 2: ストリームコンテキストを作成して setStreamContext() に渡します
$context = stream_context_create($options);
$adapter->setStreamContext($context);

// 方法 3: デフォルトのストリームコンテキストを取得してオプションを設定します
$context = $adapter->getStreamContext();
stream_context_set_option($context, $options);

// リクエストを処理します
$response = $client->request();

// すべてがうまくいけば、これでまたコンテキストにアクセスできます
$opts = stream_context_get_options($adapter->getStreamContext());
echo $opts['ssl']['peer_certificate'];
]]></programlisting>
            </example>

            <note>
                <para>
                    ストリームコンテキストのオプションは、
                    アダプタが実際にリクエストを処理しだす前に設定しなければならないことに注意しましょう。
                    コンテキストを設定せずにソケットアダプタで <acronym>HTTP</acronym> リクエストを処理すると、
                    デフォルトのストリームコンテキストが作成されます。
                    リクエストを処理した後にこのコンテキストリソースにアクセスするには
                    <methodname>getStreamContext()</methodname> メソッドを使用します。
                </para>
            </note>
        </sect3>
    </sect2>

    <sect2 id="zend.http.client.adapters.proxy">
        <title>プロキシアダプタ</title>

        <para>
            <classname>Zend_Http_Client_Adapter_Proxy</classname> アダプタはデフォルトのソケットアダプタとほぼ同じです。
            ただし、対象となるサーバに直接接続するのではなく
            <acronym>HTTP</acronym> プロキシサーバを経由して接続するという点が異なります。
            これにより、<classname>Zend_Http_Client</classname> をプロキシサーバの中から使用できるようになります。
            セキュリティやパフォーマンス上の理由により、これが必要となる場合もあるでしょう。
        </para>

        <para>
            プロキシアダプタを使用するには、
            デフォルトの 'adapter' オプション以外に
            いくつか追加のパラメータを設定する必要があります。

            <table id="zend.http.client.adapters.proxy.table">
                <title>Zend_Http_Client の設定パラメータ</title>

                <tgroup cols="4">
                    <thead>
                        <row>
                            <entry>パラメータ</entry>
                            <entry>説明</entry>
                            <entry>想定している型</entry>
                            <entry>値の例</entry>
                        </row>
                    </thead>

                    <tbody>
                        <row>
                            <entry>proxy_host</entry>
                            <entry>プロキシサーバのアドレス</entry>
                            <entry>string</entry>
                            <entry>'proxy.myhost.com' あるいは '10.1.2.3'</entry>
                        </row>

                        <row>
                            <entry>proxy_port</entry>
                            <entry>プロキシサーバの <acronym>TCP</acronym> ポート</entry>
                            <entry>integer</entry>
                            <entry>8080 (デフォルト) あるいは 81</entry>
                        </row>

                        <row>
                            <entry>proxy_user</entry>
                            <entry>必要に応じて、プロキシのユーザ名</entry>
                            <entry>string</entry>
                            <entry>'shahar' あるいは指定しない場合は '' (デフォルト)</entry>
                        </row>

                        <row>
                            <entry>proxy_pass</entry>
                            <entry>必要に応じて、プロキシのパスワード</entry>
                            <entry>string</entry>
                            <entry>'secret' あるいは指定しない場合は '' (デフォルト)</entry>
                        </row>

                        <row>
                            <entry>proxy_auth</entry>
                            <entry>プロキシの <acronym>HTTP</acronym> 認証形式</entry>
                            <entry>string</entry>
                            <entry>Zend_Http_Client::AUTH_BASIC (デフォルト)</entry>
                        </row>
                    </tbody>
                </tgroup>
            </table>
        </para>

        <para>
            proxy_host は常に設定しなければなりません。指定しなかった場合は、
            自動的に <classname>Zend_Http_Client_Adapter_Socket</classname> による直接接続に切り替わります。
            proxy_port のデフォルトは '8080' です。もし別のポートをプロキシで使用している場合は、
            適切に設定する必要があります。
        </para>

        <para>
            proxy_user および proxy_pass は、
            プロキシサーバが認証を必要とする場合にのみ設定します。
            これらを指定すると、'Proxy-Authentication'
            ヘッダがリクエストに追加されます。プロキシで認証を必要としない場合は、
            このふたつのオプションはそのままにしておきます。
        </para>

        <para>
            proxy_auth は、プロキシが認証を必要としている場合に、
            その認証形式を指定します。設定できる値は
            Zend_Http_Client::setAuth() メソッドと同じです。現在はベーシック認証
            (Zend_Http_Client::AUTH_BASIC) のみをサポートしています。
        </para>

        <example id="zend.http.client.adapters.proxy.example-1">
            <title>プロキシサーバを使用した Zend_Http_Client の使用法</title>

            <programlisting language="php"><![CDATA[
// 接続パラメータを設定します
$config = array(
    'adapter'    => 'Zend_Http_Client_Adapter_Proxy',
    'proxy_host' => 'proxy.int.zend.com',
    'proxy_port' => 8000,
    'proxy_user' => 'shahar.e',
    'proxy_pass' => 'bananashaped'
);

// クライアントオブジェクトのインスタンスを作成します
$client = new Zend_Http_Client('http://www.example.com', $config);

// 作業を続けます...
]]></programlisting>
        </example>

        <para>
            説明したとおり、もし proxy_host を省略したり空文字列を設定したりすると、
            自動的に直接接続に切り替わります。これにより、設定パラメータによって
            オプションでプロキシを使用できるようなアプリケーションを書けるようになります。
        </para>

        <note>
            <para>
                プロキシアダプタは <classname>Zend_Http_Client_Adapter_Socket</classname>
                を継承しているので、ストリームコンテキストへのアクセスメソッド
                (<link linkend="zend.http.client.adapters.socket.streamcontext">このセクション</link>を参照してください)
                を使用してプロキシ接続におけるストリームコンテキストオプションを設定できます。
                その方法については上で説明しました。
            </para>
        </note>
    </sect2>

    <sect2 id="zend.http.client.adapters.curl">
        <title>cURL アダプタ</title>

        <para>
            cURL は標準的な <acronym>HTTP</acronym> クライアントライブラリで、
            多くの OS に含まれています。また <acronym>PHP</acronym> からは cURL
            拡張モジュールで使用できます。
            <acronym>HTTP</acronym> クライアントで起こりうる多くの特別な例にも対応することができるので、
            <acronym>HTTP</acronym> アダプタとしては完璧な選択肢といえるでしょう。
            セキュアな接続やプロキシ、そしてあらゆる種類の認証にも対応しており、
            大きなファイルをサーバ間で移動させるときなどにも使用できます。
        </para>

        <example id="zend.http.client.adapters.curl.example-1">
            <title>cURL オプションの設定</title>

            <programlisting language="php"><![CDATA[
$config = array(
    'adapter'   => 'Zend_Http_Client_Adapter_Curl',
    'curloptions' => array(CURLOPT_FOLLOWLOCATION => true),
);
$client = new Zend_Http_Client($uri, $config);
]]></programlisting>
        </example>

        <para>
            デフォルトでは、cURL アダプタは
            Socket アダプタとまったく同じ挙動となるように設定されています。
            また、Socket アダプタおよび Proxy アダプタと同じ設定パラメータを使えます。
            cURL のオプションを変更するには、アダプタのコンストラクタでキー
            'curloptions' を指定するか、あるいは
            <methodname>setCurlOption($name, $value)</methodname> をコールします。
            <code>$name</code> は、cURL 拡張モジュールの
            CURL_* 定数に対応します。Curl ハンドルにアクセスするには
            <command>$adapter->getHandle();</command> をコールします。
        </para>

        <example id="zend.http.client.adapters.curl.example-2">
            <title>ハンドルによるファイル転送</title>

            <para>
                cURL を使用して、巨大なファイルを <acronym>HTTP</acronym> 越しに転送できます。
            </para>

            <programlisting language="php"><![CDATA[
$putFileSize   = filesize("filepath");
$putFileHandle = fopen("filepath", "r");

$adapter = new Zend_Http_Client_Adapter_Curl();
$client = new Zend_Http_Client();
$client->setAdapter($adapter);
$adapter->setConfig(array(
    'curloptions' => array(
        CURLOPT_INFILE => $putFileHandle,
        CURLOPT_INFILESIZE => $putFileSize
    )
));
$client->request("PUT");
]]></programlisting>
        </example>
    </sect2>

    <sect2 id="zend.http.client.adapters.test">
        <title>テストアダプタ</title>

        <para>
            <acronym>HTTP</acronym> 接続に依存するテストコードを書くのは非常に難しいものです。
            たとえば、リモートサーバから <acronym>RSS</acronym> を取得するアプリケーションをテストするには、
            ネットワークにつながっている必要があります。常にネットワークが使用できるとは限りません。
        </para>

        <para>
            このようなときのためにあるのが <classname>Zend_Http_Client_Adapter_Test</classname> アダプタです。
            <classname>Zend_Http_Client</classname> を使用するアプリケーションを作成し、それをテストしたい場合には、
            デフォルトのアダプタを Test アダプタ (モックオブジェクト) に変更します。
            これで、サーバに接続せずにテストを行えるようになります。
        </para>

        <para>
            <classname>Zend_Http_Client_Adapter_Test</classname> には setResponse() というメソッドがあります。
            このメソッドのパラメータには、<acronym>HTTP</acronym> レスポンスをテキストか
            <classname>Zend_Http_Response</classname> オブジェクトで指定できます。
            レスポンスを設定すると、Test アダプタは常にこのレスポンスを返すようになります。
            実際の <acronym>HTTP</acronym> リクエストは行いません。
        </para>

        <example id="zend.http.client.adapters.test.example-1">
            <title>HTTP レスポンススタブを使用したテスト</title>

            <programlisting language="php"><![CDATA[
// 新しいアダプタとクライアントのインスタンスを作成します
$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
    'adapter' => $adapter
));

// 想定するレスポンスを設定します
$adapter->setResponse(
    "HTTP/1.1 200 OK"        . "\r\n" .
    "Content-type: text/xml" . "\r\n" .
                               "\r\n" .
    '<?xml version="1.0" encoding="UTF-8"?>' .
    '<rss version="2.0" ' .
    '     xmlns:content="http://purl.org/rss/1.0/modules/content/"' .
    '     xmlns:wfw="http://wellformedweb.org/CommentAPI/"' .
    '     xmlns:dc="http://purl.org/dc/elements/1.1/">' .
    '  <channel>' .
    '    <title>Premature Optimization</title>' .
    // などなど...
    '</rss>');

$response = $client->request('GET');
// .. $response の処理を続けます...
]]></programlisting>
        </example>

        <para>
            上の例のようにすると、<acronym>HTTP</acronym> クライアントにお望みのレスポンスを返させることができます。
            その際にネットワーク接続は使用しません。また、実際のサーバからのレスポンスも使用しません。
            この場合、このテストでテストするのは、
            レスポンス本文の <acronym>XML</acronym> をアプリケーションが正しくパースできるかどうかということです。
        </para>

        <para>
            時には、オブジェクトに対するひとつのメソッド呼び出しの中で複数の
            <acronym>HTTP</acronym> トランザクションを行うこともあるでしょう。そのような場合は
            setResponse() を単独で使うことはできません。なぜなら、
            結果が呼び出し元に返ってくるまで次のレスポンスを設定できないからです。
        </para>

        <example id="zend.http.client.adapters.test.example-2">
            <title>複数の HTTP レスポンススタブを使用したテスト</title>

            <programlisting language="php"><![CDATA[
// 新しいアダプタおよびクライアントのインスタンスを作成します
$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
    'adapter' => $adapter
));

// 最初の応答として期待する値を設定します
$adapter->setResponse(
    "HTTP/1.1 302 Found"      . "\r\n" .
    "Location: /"             . "\r\n" .
    "Content-Type: text/html" . "\r\n" .
                                "\r\n" .
    '<html>' .
    '  <head><title>Moved</title></head>' .
    '  <body><p>This page has moved.</p></body>' .
    '</html>');

// それに続くレスポンスを設定します
$adapter->addResponse(
    "HTTP/1.1 200 OK"         . "\r\n" .
    "Content-Type: text/html" . "\r\n" .
                                "\r\n" .
    '<html>' .
    '  <head><title>My Pet Store Home Page</title></head>' .
    '  <body><p>...</p></body>' .
    '</html>');

// HTTP クライアントオブジェクト ($client) をテスト対象の
// オブジェクトに注入し、オブジェクトの動きを以下でテストします
]]></programlisting>
        </example>

        <para>
            setResponse() メソッドは、
            <classname>Zend_Http_Client_Adapter_Test</classname> のバッファにあるレスポンスをすべて削除し、
            最初に返されるレスポンスを設定します。addResponse()
            メソッドは、それに続くレスポンスを追加します。
        </para>

        <para>
            レスポンスは、それを追加した順に再生されます。
            登録したよりも多くのリクエストが発生した場合は、
            返されるレスポンスは最初のものに戻り、そこからまた順に返されるようになります。
        </para>

        <para>
            上の例で、このアダプタがテストするように設定されているのは、
            302 リダイレクトが発生した場合のオブジェクトの挙動です。
            アプリケーションの内容によって、リダイレクトさせるべきなのかそうでないのかは異なるでしょう。
            この例ではリダイレクトさせることを想定しているので、
            テストアダプタもそれにあわせて設定しています。
            最初の 302 レスポンスを setResponse() メソッドで設定し、
            次に返される 200 レスポンスを addResponse() メソッドで設定します。
            テストアダプタを設定し終えたら、そのアダプタを含む <acronym>HTTP</acronym>
            クライアントをテスト対象オブジェクトに注入し、その挙動をテストします。
        </para>

        <para>
            アダプタをわざと失敗させたい場合は
            <methodname>setNextRequestWillFail($flag)</methodname> を使用します。
            このメソッドは、次に <methodname>connect()</methodname> をコールしたときに
            <classname>Zend_Http_Client_Adapter_Exception</classname>
            を発生させます。これは、外部のサイトのコンテンツをキャッシュするアプリケーションで、
            (外部サイトがダウンしていたときの) 挙動をテストする際に有用です。
        </para>

        <example id="zend.http.client.adapters.test.example-3">
            <title>アダプタを失敗させる</title>

            <programlisting language="php"><![CDATA[
// 新たなアダプタとクライアントを作成します
$adapter = new Zend_Http_Client_Adapter_Test();
$client = new Zend_Http_Client('http://www.example.com', array(
    'adapter' => $adapter
));

// 次のリクエストでわざと例外を発生させます
$adapter->setNextRequestWillFail(true);

try {
    // これは Zend_Http_Client_Adapter_Exception となります
    $client->request();
} catch (Zend_Http_Client_Adapter_Exception $e) {
    // ...
}

// これ以降の処理は、 setNextRequestWillFail(true) を次に呼び出すまで
//通常通りに行います
]]></programlisting>
        </example>
    </sect2>

    <sect2 id="zend.http.client.adapters.extending">
        <title>独自の接続アダプタの作成</title>

        <para>
            独自の接続アダプタを作成し、それを使用することもできます。
            たとえば持続的なソケットを使用するアダプタを作成したり、
            キャッシュ機能を追加したアダプタを作成したりなど、
            作成するアプリケーションの要件にあわせたものを作成することが可能です。
        </para>

        <para>
            そのためには、<classname>Zend_Http_Client_Adapter_Interface</classname>
            を実装したクラスを作成する必要があります。
            以下の例は、ユーザ定義のアダプタクラスの雛形となります。
            この例で定義されているすべてのパブリック関数を、
            アダプタで定義する必要があります。
        </para>

        <example id="zend.http.client.adapters.extending.example-1">
            <title>独自の接続アダプタの作成</title>

            <programlisting language="php"><![CDATA[
class MyApp_Http_Client_Adapter_BananaProtocol
    implements Zend_Http_Client_Adapter_Interface
{
    /**
     * アダプタの設定配列を設定する
     *
     * @param array $config
     */
    public function setConfig($config = array())
    {
        // ここはほとんど変更することはありません -
        // 通常は Zend_Http_Client_Adapter_Socket の実装をコピーします
    }

    /**
     * リモートサーバに接続する
     *
     * @param string  $host
     * @param int     $port
     * @param boolean $secure
     */
    public function connect($host, $port = 80, $secure = false)
    {
        // リモートサーバとの接続を確立します
    }

    /**
     * リクエストをリモートサーバに送信する
     *
     * @param string        $method
     * @param Zend_Uri_Http $url
     * @param string        $http_ver
     * @param array         $headers
     * @param string        $body
     * @return string Request as text
     */
    public function write($method,
                          $url,
                          $http_ver = '1.1',
                          $headers = array(),
                          $body = '')
    {
        // リクエストをリモートサーバに送信します。
        // この関数は、リクエスト全体 (ヘッダおよび本文)
        // を文字列で返します。
    }

    /**
     * サーバからのレスポンスを読み込む
     *
     * @return string
     */
    public function read()
    {
        // リモートサーバからのレスポンスを読み込み、それを文字列で返します。
    }

    /**
     * サーバとの接続を閉じる
     *
     */
    public function close()
    {
        // リモートサーバとの接続を閉じます。最後にコールされます。
    }
}

// そして、このアダプタを使用します
$client = new Zend_Http_Client(array(
    'adapter' => 'MyApp_Http_Client_Adapter_BananaProtocol'
));
]]></programlisting>
        </example>
    </sect2>
</sect1>
