<?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/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Apelog &#187; zendframework</title>
	<atom:link href="http://blog.apecell.com/tag/zendframework/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.apecell.com</link>
	<description>Apecell's blog by Design</description>
	<lastBuildDate>Tue, 22 Jun 2010 07:08:30 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Zend_MailのFromヘッダでDoCoMoから返信が出来ない</title>
		<link>http://blog.apecell.com/2008/05/31/id/39</link>
		<comments>http://blog.apecell.com/2008/05/31/id/39#comments</comments>
		<pubDate>Sat, 31 May 2008 09:10:17 +0000</pubDate>
		<dc:creator>design</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Program]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://blog.apecell.com/?p=39</guid>
		<description><![CDATA[Zend_Mailでメールする際のFromヘッダ作成時にメールアドレスのみ渡して名前を渡さない場合
"" &#60;foo@bar.com&#62;
の様な形で生成されてしまう。
この状態でDoCoMo宛にメール送信を行うとDoCoMo端末から返信が出来なかった（確認したのはD905とPROSOLID μ）
ダブルクォーテーションで囲われた所が無ければ返信が出来たのでFromヘッダ生成メソッド部を変更。

public function setFrom($email, $name = '')
{
    if ($this-&#62;_from === null) {
        $email = strtr($email,&#34;\r\n\t&#34;,'???');
        $this-&#62;_from = $email;

        $this-&#62;_storeHeader('From', $email, true);
    } else {
    [...]]]></description>
			<content:encoded><![CDATA[<p>Zend_Mailでメールする際のFromヘッダ作成時にメールアドレスのみ渡して名前を渡さない場合</p>
<pre>"" &lt;foo@bar.com&gt;</pre>
<p>の様な形で生成されてしまう。</p>
<p>この状態でDoCoMo宛にメール送信を行うとDoCoMo端末から返信が出来なかった（確認したのはD905とPROSOLID μ）</p>
<p>ダブルクォーテーションで囲われた所が無ければ返信が出来たのでFromヘッダ生成メソッド部を変更。</p>
<pre name="code" class="php">
public function setFrom($email, $name = '')
{
    if ($this-&gt;_from === null) {
        $email = strtr($email,&quot;\r\n\t&quot;,'???');
        $this-&gt;_from = $email;

        $this-&gt;_storeHeader('From', $email, true);
    } else {
        /**
         * Error
         */
    }
    return $this;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.apecell.com/2008/05/31/id/39/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ZendFrameworkでfindAllBy{Field}メソッドを使う</title>
		<link>http://blog.apecell.com/2008/01/22/id/31</link>
		<comments>http://blog.apecell.com/2008/01/22/id/31#comments</comments>
		<pubDate>Mon, 21 Jan 2008 15:00:00 +0000</pubDate>
		<dc:creator>design</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Program]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://blog.apecell.com/1970/01/01/31</guid>
		<description><![CDATA[RailsやCakePHPなどのフレームワークではお馴染みのfindBy系メソッドをZendFrameworkで実装したいということで。
Zend_Db_Tableクラスを継承したMyZend_Db_Tableクラス内のマジックメソッドで実装し、ModelはMyZend_Db_Tableを継承する。

&#60;?php
class MyZend_Db_Table extends Zend_Db_Table {
    /**
     * 論理削除カラム名
     * @var string
     */
    private $_deleteCol = 'delete_time';

    /**
     * findAllBy[ColName]($value [, $flag])でデータアクセス
     *
     [...]]]></description>
			<content:encoded><![CDATA[<p>RailsやCakePHPなどのフレームワークではお馴染みのfindBy系メソッドをZendFrameworkで実装したいということで。</p>
<p>Zend_Db_Tableクラスを継承したMyZend_Db_Tableクラス内のマジックメソッドで実装し、ModelはMyZend_Db_Tableを継承する。</p>
<pre name="code" class="php">
&lt;?php
class MyZend_Db_Table extends Zend_Db_Table {
    /**
     * 論理削除カラム名
     * @var string
     */
    private $_deleteCol = 'delete_time';

    /**
     * findAllBy[ColName]($value [, $flag])でデータアクセス
     *
     * $flag = true で論理削除された行は除外して取得
     *
     * @param string $method
     * @param array  $args
     * @return Zend_Db_Table_Row_Abstract
     */
    public function __call($method, $args) {
        if (preg_match('/^findAllBy(\w+)?$/', $method, $matches)) {
            $field = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $matches[1]));

            $where = array();
            $where[&quot;`$field` = ?&quot;] = $args[0];

            if (isset($args[1]) &amp;&amp; $args[1] === true
                &amp;&amp; in_array($this-&gt;_deleteCol, $this-&gt;_cols)) {
                $where[] = &quot;`{$this-&gt;_deleteCol}` IS NULL&quot;;
            }
            return $this-&gt;fetchAll($where);
        }
        throw new Zend_Db_Table_Exception(&quot;Call undefine method $method()&quot;);
    }
}
</pre>
<p>これで<em>$model-&#62;findAllByName(&#8217;Design&#8217;);</em>のようにアクセスすれば<em>`name` = &#8216;Design&#8217;</em>という条件でのデータアクセスが可能になる。</p>
<p>データは論理削除する事が多いのでfindAllByName(&#8217;Design&#8217;, true)の形の呼び出しで<br /><em>`name` = &#8216;Design&#8217; AND `delete_time` IS NULL</em></p>
<p>有効な行のみ返すようにしている。</p>
<p>まぁそんな感じで移植実装がおこなわれていくわけです。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.apecell.com/2008/01/22/id/31/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHPでOpenIDによるログイン処理</title>
		<link>http://blog.apecell.com/2007/10/28/id/20</link>
		<comments>http://blog.apecell.com/2007/10/28/id/20#comments</comments>
		<pubDate>Sat, 27 Oct 2007 15:00:00 +0000</pubDate>
		<dc:creator>design</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Program]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[openid]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://blog.apecell.com/1970/01/01/20</guid>
		<description><![CDATA[PHPでのOpenIDを利用したログイン認証の実装について。
OpenIDの概要は調べるかWebの分散ID認証システムについてにて。とりあえず実装してみて、という感じなので間違っていたら指摘お願いします。
OpenID EnabledのPHP用ライブラリを利用する。
他にもVidentity.orgやPHP ClassesにOpenIDのライブラリはあるが更新が止まっていたり簡易的なものだったりするのでOpenID Enabledのものを使用。
実行環境

WindowsXP SP2
PHP 5.2.3
PHP OpenID Library 2.0.0-rc2

PHP OpenID Library 1.x.x系統と若干実装が違うので互換性は無い。
サンプルを動かしてみる
ライブラリを解凍するとexamplesディレクトリがある、コンシューマ側なのでexamples/consumerを実行してみる。
OpenID関連で生成されるファイル格納ディレクトリが作れないとエラーが出た。デフォルトで「/tmp/_php_consumer_test」に作るようになっているので「/tmp」を作ってやる（Windowsで「/tmp」は、Dドライブで実行しているなら「D:\tmp」）。
次にOpenIDで使用する暗号生成部でエラーになった。追ってみるとデフォルトで「/dev/urandom」を使用するようになっている。「/dev/urandom」はカーネル乱数ジェネレータでWindowsには無い。
定数Auth_OpenID_RAND_SOURCEがNULLの場合、PHP内で乱数を生成するのでWindowsの場合は先に以下のようにNULLで定数定義する。

&#60;?php
// Windowsの場合カーネル乱数ジェネレータを使用しない
if (!strncmp(PHP_OS, 'WIN', 3)) {
    define('Auth_OpenID_RAND_SOURCE', NULL);
}

この2点の変更で動作確認は出来た。確認にはOpenID.ne.jpを使用。
OpenIDでの認証をアプリケーションに組み込むために
組み込む為には入力されたIDとアプリケーションのデータ（会員ID）を結び付ける必要がある。
先に会員登録としてOpenIDを入力させて登録させる形式より、先に認証をおこない認可された場合ログインフラグを立ててアプリケーションデータと比較し、無ければ入力したIDと取得したデータ（ニックネームやメールアドレス）を登録する方がOpenIDで管理している情報を利用できるのでスマート。
取得したデータ以外に必要な情報があれば、認証時に登録画面に遷移。OpenID1.0で登録できる情報はE-mail、ニックネーム、氏名、性別、国籍、郵便番号、言語、生年月日。OpenID2.0ではプロトコルにXRIが使えてもう少し詳細な情報がやりとりできるらしい。
ユーザーから入力されたIDと結果として取得できるIDは違う場合があるので認証リダイレクト前に一度セッションに格納してから認可後にセッションから取得した値をアプリケーション側に登録する必要がある。
Zend Frameworkで使用
軽くラッピングしてZend Frameworkで使ってみた。
とりあえずザッと書いて動かしてみたものを以下に。
Zend_Controller_Actionを継承してpreDispatch()に認証処理を実装、実際のControllerはこのクラスを継承する。デフォルトで認証をおこなうようになっているので、認証が必要ない場合は$this-&#62;checkLogin = false;でオーバーライド。

&#60;?php
class Sample_Controller_Action_Base extends Zend_Controller_Action {
    /**
     * @var bool ログインチェックフラグ
     */
    protected $checkLogin = true;

  [...]]]></description>
			<content:encoded><![CDATA[<p>PHPでのOpenIDを利用したログイン認証の実装について。</p>
<p>OpenIDの概要は調べるか<a href="http://blog.apecell.com/archives/310800.html" target="_blank">Webの分散ID認証システムについて</a>にて。とりあえず実装してみて、という感じなので間違っていたら指摘お願いします。</p>
<p><a href="http://www.openidenabled.com/php-openid/" target="_blank">OpenID Enabled</a>のPHP用ライブラリを利用する。</p>
<p>他にも<a href="http://videntity.org/openid/" target="_blank">Videntity.org</a>や<a href="http://www.phpclasses.org/" target="_blank">PHP Classes</a>にOpenIDのライブラリはあるが更新が止まっていたり簡易的なものだったりするのでOpenID Enabledのものを使用。</p>
<h4>実行環境</h4>
<ul>
<li>WindowsXP SP2</li>
<li>PHP 5.2.3</li>
<li>PHP OpenID Library 2.0.0-rc2</li>
</ul>
<p>PHP OpenID Library 1.x.x系統と若干実装が違うので互換性は無い。</p>
<h4>サンプルを動かしてみる</h4>
<p>ライブラリを解凍するとexamplesディレクトリがある、コンシューマ側なのでexamples/consumerを実行してみる。</p>
<p>OpenID関連で生成されるファイル格納ディレクトリが作れないとエラーが出た。デフォルトで「/tmp/_php_consumer_test」に作るようになっているので「/tmp」を作ってやる（Windowsで「/tmp」は、Dドライブで実行しているなら「D:\tmp」）。</p>
<p>次にOpenIDで使用する暗号生成部でエラーになった。追ってみるとデフォルトで「/dev/urandom」を使用するようになっている。「/dev/urandom」はカーネル乱数ジェネレータでWindowsには無い。</p>
<p>定数Auth_OpenID_RAND_SOURCEがNULLの場合、PHP内で乱数を生成するのでWindowsの場合は先に以下のようにNULLで定数定義する。</p>
<pre name="code" class="php">
&lt;?php
// Windowsの場合カーネル乱数ジェネレータを使用しない
if (!strncmp(PHP_OS, 'WIN', 3)) {
    define('Auth_OpenID_RAND_SOURCE', NULL);
}
</pre>
<p>この2点の変更で動作確認は出来た。確認には<a href="http://www.openid.ne.jp/">OpenID.ne.jp</a>を使用。</p>
<h4>OpenIDでの認証をアプリケーションに組み込むために</h4>
<p>組み込む為には入力されたIDとアプリケーションのデータ（会員ID）を結び付ける必要がある。</p>
<p>先に会員登録としてOpenIDを入力させて登録させる形式より、先に認証をおこない認可された場合ログインフラグを立ててアプリケーションデータと比較し、無ければ入力したIDと取得したデータ（ニックネームやメールアドレス）を登録する方がOpenIDで管理している情報を利用できるのでスマート。</p>
<p>取得したデータ以外に必要な情報があれば、認証時に登録画面に遷移。OpenID1.0で登録できる情報はE-mail、ニックネーム、氏名、性別、国籍、郵便番号、言語、生年月日。OpenID2.0ではプロトコルにXRIが使えてもう少し詳細な情報がやりとりできるらしい。</p>
<p>ユーザーから入力されたIDと結果として取得できるIDは違う場合があるので認証リダイレクト前に一度セッションに格納してから認可後にセッションから取得した値をアプリケーション側に登録する必要がある。</p>
<h4>Zend Frameworkで使用</h4>
<p>軽くラッピングしてZend Frameworkで使ってみた。</p>
<p>とりあえずザッと書いて動かしてみたものを以下に。</p>
<p>Zend_Controller_Actionを継承してpreDispatch()に認証処理を実装、実際のControllerはこのクラスを継承する。デフォルトで認証をおこなうようになっているので、認証が必要ない場合は$this-&#62;checkLogin = false;でオーバーライド。</p>
<pre name="code" class="php">
&lt;?php
class Sample_Controller_Action_Base extends Zend_Controller_Action {
    /**
     * @var bool ログインチェックフラグ
     */
    protected $checkLogin = true;

    /**
     * @var Zend_Session
     */
    public $session;

    /**
     * 初期化
     */
    public function init() {
        $this-&gt;session = new Zend_Session_Namespace();
    }

    /**
     * preDispatch
     */
    public function preDispatch() {
        // ログイン認証
        if ($this-&gt;checkLogin &amp;&amp; !$this-&gt;session-&gt;login) {
            $auth = new Sample_Auth_OpenID();

            if (!empty($_REQUEST['openid_url'])) {
                $this-&gt;session-&gt;openid_url = $_REQUEST['openid_url'];
                $process_path = '/home'; // 適当に遷移に合わせて

                $auth-&gt;authenticate($_REQUEST['openid_url'], $process_path);
            }

            // 認可結果判別
            if ($auth-&gt;checkResult()) {
                // 認可時
                $this-&gt;session-&gt;login = true;

                echo $this-&gt;session-&gt;openid_url;
                print_r($auth-&gt;getContents());
            } else {
                // 拒否/失敗
                $this-&gt;session-&gt;destroy();
                echo 'Auth failed...';
            }
        }
    }
}
</pre>
<p>で、以下がOpenIDの認証用クラス。といってもexample纏めた程度。</p>
<pre name="code" class="php">
&lt;?php
class Sample_Auth_OpenID {
    /**
     * @var Auth_OpenID_Consumer
     */
    protected $_consumer = NULL;

    /**
     * OpenID関連で生成されるファイル格納ディレクトリパス
     * @var string
     */
    public $_store_path = &quot;/tmp/_php_consumer&quot;;

    /**
     * 承認フラグ
     * @var bool
     */
    protected $_valid = false;

    /**
     * 認証レスポンス
     * @var object
     */
    protected $_response = NULL;

    /**
     * 取得内容
     * @var array
     */
    protected $_contents = array();

    /**
     * コンストラクタ
     */
    public function __construct() {
        // Windowsの場合カーネル乱数ジェネレータを使用しない
        if (!strncmp(PHP_OS, 'WIN', 3)) {
            define('Auth_OpenID_RAND_SOURCE', NULL);
        }

        if (!file_exists($this-&gt;_store_path) &amp;&amp; !mkdir($this-&gt;_store_path)) {
            die(&quot;Could not create the FileStore directory&quot;);
        }

        $this-&gt;_consumer = new Auth_OpenID_Consumer(new Auth_OpenID_FileStore($this-&gt;_store_path));

        require_once &quot;Auth/OpenID/SReg.php&quot;;
    }
    /**
     * OpenIDによる認証
     *
     * @param string $checkid
     * @param string $process_path
     * @return bool 認証失敗時
     */
    public function authenticate($checkid, $process_path) {
        // 接続スキーマ
        $scheme = 'http';
        $scheme = (isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';

        // 承認URL
        $trust_root = sprintf(&quot;$scheme://%s:%s%s&quot;,
        $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'],
        dirname($_SERVER['PHP_SELF']));

        // 承認後リダイレクト先URL
        $process_url = $trust_root . $process_path;

        // 認証開始
        $auth_request = $this-&gt;_consumer-&gt;begin($checkid);

        // 入力されたOpenIDが使用出来ず失敗
        if (!$auth_request) {
            return false;
        }

        // 認証時に取得するデータ
        $sreg_request = Auth_OpenID_SRegRequest::build(
                                     // Required
                                     array('nickname'),
                                     // Optional
                                     array('fullname', 'email'));

        if ($sreg_request) {
            $auth_request-&gt;addExtension($sreg_request);
        }

        // 承認の為リダイレクト
        if ($auth_request-&gt;shouldSendRedirect()) {
            $redirect_url = $auth_request-&gt;redirectURL($trust_root, $process_url);

            // If the redirect URL can't be built, display an error
            // message.
            if (Auth_OpenID::isFailure($redirect_url)) {
                displayError(&quot;Could not redirect to server: &quot; . $redirect_url-&gt;message);
            } else {
                // Send redirect.
                header(&quot;Location: &quot;.$redirect_url);
                exit;
            }
        }
    }

    /**
     * 認証結果判別
     *
     * @return bool 認証可否
     */
    public function checkResult() {
        $this-&gt;_response = $this-&gt;_consumer-&gt;complete();

        // 認可時のみ値セット
        if ($this-&gt;_response-&gt;status == Auth_OpenID_SUCCESS) {
            $this-&gt;_valid = true;
            $this-&gt;_contents = Auth_OpenID_SRegResponse::fromSuccessResponse($this-&gt;_response)-&gt;contents();

            $id = ($this-&gt;_response-&gt;endpoint-&gt;canonicalID) ? $this-&gt;_response-&gt;endpoint-&gt;canonicalID : $this-&gt;_response-&gt;identity_url;
        }

        return $this-&gt;isValid();
    }

    /**
     * @var bool 認可結果
     */
    public function isValid() {
        return $this-&gt;_valid;
    }

    /**
     * @return array 取得情報
     */
    public function getContents() {
        return $this-&gt;_contents;
    }
}
</pre>
<p>認証APIやプロトコル仕様が乱立してるけど何が主流になるやら。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.apecell.com/2007/10/28/id/20/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>なぜPHPのautoload()が早いのか</title>
		<link>http://blog.apecell.com/2007/10/22/id/19</link>
		<comments>http://blog.apecell.com/2007/10/22/id/19#comments</comments>
		<pubDate>Sun, 21 Oct 2007 15:00:00 +0000</pubDate>
		<dc:creator>design</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Program]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://blog.apecell.com/1970/01/01/19</guid>
		<description><![CDATA[__autoload()が早いというよりも、class_exists()に比べてrequre_once()、include_once()が遅いからというもの（クラスの読み込み判定の場合）。
通常__autoload()内でクラスの有無を調べて無ければ読み込みを行う。一度しか呼ばれないものならその場で読み込んだほうが早いが、複数回読み込み判定がおこなわれるものがある場合（Superクラスなど）一度autoload経由でclass_exists()の篩いにかけた方が良い。
PHP5のフレームワークではほとんどautoload系の読み込み実装がなされている事からも、その差は結構大きいので不特定回数読み込まれるファイルが多数ある場合は注意。
以下の動作環境で最も単純なクラス( class Sample{} )を1000回読み込んでインスタンス生成した場合、class_exists()で見つからなければrequire()と、常にrequire_once()だと100倍以上差があった。

PHP 5.2.3
WindowsXP SP2
AMD Athlon&#x2122;  64 Processor 3500+ 1.79GHz
2.00GB RAM

1000回require_once() &#8211; 0.450819秒

&#60;?php
for ($i=0;$i&#60;1000;$i++) {
    require_once('Sample.php');
    $sample = new Sample();
}


----------------------------------------------------
marker  time index            ex time         perct
----------------------------------------------------
Start   [...]]]></description>
			<content:encoded><![CDATA[<p>__autoload()が早いというよりも、class_exists()に比べてrequre_once()、include_once()が遅いからというもの（クラスの読み込み判定の場合）。</p>
<p>通常__autoload()内でクラスの有無を調べて無ければ読み込みを行う。一度しか呼ばれないものならその場で読み込んだほうが早いが、<em>複数回読み込み判定がおこなわれるものがある場合</em>（Superクラスなど）一度autoload経由でclass_exists()の篩いにかけた方が良い。</p>
<p>PHP5のフレームワークではほとんどautoload系の読み込み実装がなされている事からも、その差は結構大きいので不特定回数読み込まれるファイルが多数ある場合は注意。</p>
<p>以下の動作環境で最も単純なクラス( class Sample{} )を1000回読み込んでインスタンス生成した場合、class_exists()で見つからなければrequire()と、常にrequire_once()だと100倍以上差があった。</p>
<ul>
<li>PHP 5.2.3</li>
<li>WindowsXP SP2</li>
<li>AMD Athlon&#x2122;  64 Processor 3500+ 1.79GHz</li>
<li>2.00GB RAM</li>
</ul>
<h4>1000回require_once() &#8211; 0.450819秒</h4>
<pre name="code" class="php">
&lt;?php
for ($i=0;$i&lt;1000;$i++) {
    require_once('Sample.php');
    $sample = new Sample();
}
</pre>
<pre>
----------------------------------------------------
marker  time index            ex time         perct
----------------------------------------------------
Start   1193042528.49833500   -                0.00%
----------------------------------------------------
Stop    1193042528.94915400   0.450819       100.00%
----------------------------------------------------
</pre>
<h4>999回class_exists(), 1回require() &#8211; 0.003704秒</h4>
<pre name="code" class="php">
&lt;?php
for ($i=0;$i&lt;1000;$i++) {
    if (!class_exists('Sample', false)) {
        require('Sample.php');
    }
    $sample = new Sample();
}
</pre>
<pre>
----------------------------------------------------
marker  time index            ex time         perct
----------------------------------------------------
Start   1193042740.50069500   -                0.00%
----------------------------------------------------
Stop    1193042740.50439900   0.003704       100.00%
----------------------------------------------------
</pre>
<p>require()よりinclude()の方が早いのでinclude()にすればもう少し差は縮まるものの、なぜPHPのautoload()が早いかというとautoloadをclass_existsな実装で書く事が多いからであり、<em>autoloadの中で全てrequire_once()していたら別に早くない</em>という事。</p>
<p>クラス名の_をディレクトリとするPEAR風構成のオートローダーならZend FrameworkのZend_Loderがすぐ導入できます（Zend_LoaderとZend_Exceptionの2つで）。</p>
<p>環境違うと全然違うよ、な状態なら教えてください。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.apecell.com/2007/10/22/id/19/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Smarty互換でSmartyより軽量なTemplateLiteを使う</title>
		<link>http://blog.apecell.com/2007/10/19/id/18</link>
		<comments>http://blog.apecell.com/2007/10/19/id/18#comments</comments>
		<pubDate>Thu, 18 Oct 2007 15:00:00 +0000</pubDate>
		<dc:creator>design</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Program]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[library]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://blog.apecell.com/1970/01/01/18</guid>
		<description><![CDATA[SmartyはPHPのテンプレートエンジンでは最も有名で利用者も多いが重い。
TemplateLiteはLGPLライセンスのSmarty互換テンプレートエンジンでSmartyより早いとのこと。PHP5.1.1でSmartyとのベンチマーク比較を見る限りテンプレートで色々やってると結構差が出そう。
公式に書かれている、「TemplateLiteを使うべき7つの理由（意訳）」

Smartyよりコンパイルが早い
Smartyより表示が速い
Smartyと比較してメモリ使用量が少ない
Smartyの機能のほとんどをサポート
Smartyの代替となる
各リリースに合わせて機能追加される
活発な開発プロジェクト

6.の「各リリース」というのはSmartyに合わせてという事かな。気になるなら原文参照。
使い方もSmartyと同じなのでSmartyの重さが気になっているなら丁度良い代替になりそう。ZendFrameworkのViewとして使う場合も、Smartyの部分をTemplateLiteに置き換えればそのまま動作する。
単純なページだとそこまで差が出ないので、純粋にincludeのコストが気になる場合はSimplateなどの PHP Extention なテンプレートエンジンを使った方が良い。
以下ZendFrameworkのViewRenderer用クラス。ZendFrameworkの別テンプレートエンジン使用方法はZend FrameworkのViewをSmartyに変更するにはを参照。

&#60;?php
require_once 'Zend/View/Interface.php';
require_once 'class.template.php';

class Sample_View_TemplateLite implements Zend_View_Interface
{
    /**
     * TemplateLite object
     * @var Template_Lite
     */
    protected $_templateLite;

    /**
     * コンストラクタ
     *
   [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://smarty.php.net/" target="_blank">Smarty</a>はPHPのテンプレートエンジンでは最も有名で利用者も多いが重い。</p>
<p><a href="http://templatelite.sourceforge.net/" target="_blank">TemplateLite</a>はLGPLライセンスのSmarty互換テンプレートエンジンでSmartyより早いとのこと。PHP5.1.1で<a href="http://templatelite.sourceforge.net/images/templatelite_speed.gif" target="_blank">Smartyとのベンチマーク比較</a>を見る限りテンプレートで色々やってると結構差が出そう。</p>
<p>公式に書かれている、「TemplateLiteを使うべき7つの理由（意訳）」</p>
<ol>
<li>Smartyよりコンパイルが早い</li>
<li>Smartyより表示が速い</li>
<li>Smartyと比較してメモリ使用量が少ない</li>
<li>Smartyの機能のほとんどをサポート</li>
<li>Smartyの代替となる</li>
<li>各リリースに合わせて機能追加される</li>
<li>活発な開発プロジェクト</li>
</ol>
<p>6.の「各リリース」というのはSmartyに合わせてという事かな。気になるなら原文参照。</p>
<p>使い方もSmartyと同じなのでSmartyの重さが気になっているなら丁度良い代替になりそう。ZendFrameworkのViewとして使う場合も、Smartyの部分をTemplateLiteに置き換えればそのまま動作する。</p>
<p>単純なページだとそこまで差が出ないので、<em>純粋にincludeのコストが気になる場合</em>はSimplateなどの PHP Extention なテンプレートエンジンを使った方が良い。</p>
<p>以下ZendFrameworkのViewRenderer用クラス。ZendFrameworkの別テンプレートエンジン使用方法は<a href="http://blog.apecell.com/archives/264496.html" target="_blank">Zend FrameworkのViewをSmartyに変更するには</a>を参照。</p>
<pre name="code" class="php">
&lt;?php
require_once 'Zend/View/Interface.php';
require_once 'class.template.php';

class Sample_View_TemplateLite implements Zend_View_Interface
{
    /**
     * TemplateLite object
     * @var Template_Lite
     */
    protected $_templateLite;

    /**
     * コンストラクタ
     *
     * @param string $tmplPath
     * @param array $extraParams
     * @return void
     */
    public function __construct($tmplPath = null, $extraParams = array())
    {
        $this-&gt;_templateLite = new Template_Lite;

        if (null !== $tmplPath) {
            $this-&gt;setScriptPath($tmplPath);
        }

        foreach ($extraParams as $key =&gt; $value) {
            $this-&gt;_templateLite-&gt;$key = $value;
        }
    }

    /**
     * テンプレートエンジンオブジェクトを返します
     *
     * @return Template_Lite
     */
    public function getEngine()
    {
        return $this-&gt;_templateLite;
    }

    /**
     * テンプレートへのパスを設定します
     *
     * @param string $path パスとして設定するディレクトリ
     * @return void
     */
    public function setScriptPath($path)
    {
        if (is_readable($path)) {
            $this-&gt;_templateLite-&gt;template_dir = $path;
            return;
        }

        throw new Exception('無効なパスが指定されました');
    }

    /**
     * 現在のテンプレートディレクトリを取得します
     *
     * @return string
     */
    public function getScriptPaths()
    {
        return $this-&gt;_templateLite-&gt;template_dir;
    }

    /**
     * setScriptPath へのエイリアス
     *
     * @param string $path
     * @param string $prefix Unused
     * @return void
     */
    public function setBasePath($path, $prefix = 'Zend_View')
    {
        return $this-&gt;setScriptPath($path);
    }

    /**
     * setScriptPath へのエイリアス
     *
     * @param string $path
     * @param string $prefix Unused
     * @return void
     */
    public function addBasePath($path, $prefix = 'Zend_View')
    {
        return $this-&gt;setScriptPath($path);
    }

    /**
     * 変数をテンプレートに代入します
     *
     * @param string $key 変数名
     * @param mixed $val 変数の値
     * @return void
     */
    public function __set($key, $val)
    {
        $this-&gt;_templateLite-&gt;assign($key, $val);
    }

    /**
     * 代入された変数を取得します
     *
     * @param string $key 変数名
     * @return mixed 変数の値
     */
    public function __get($key)
    {
        return $this-&gt;_templateLite-&gt;get_template_vars($key);
    }

    /**
     * empty() や isset() のテストが動作するようにします
     *
     * @param string $key
     * @return boolean
     */
    public function __isset($key)
    {
        return (null !== $this-&gt;_templateLite-&gt;get_template_vars($key));
    }

    /**
     * オブジェクトのプロパティに対して unset() が動作するようにします
     *
     * @param string $key
     * @return void
     */
    public function __unset($key)
    {
        $this-&gt;_templateLite-&gt;clear_assign($key);
    }

    /**
     * 変数をテンプレートに代入します
     *
     * 指定したキーを指定した値に設定します。あるいは、
     * キー =&gt; 値 形式の配列で一括設定します
     *
     * @see __set()
     * @param string|array $spec 使用する代入方式 (キー、あるいは キー =&gt; 値 の配列)
     * @param mixed $value (オプション) 名前を指定して代入する場合は、ここで値を指定します
     * @return void
     */
    public function assign($spec, $value = null)
    {
        if (is_array($spec)) {
            $this-&gt;_templateLite-&gt;assign($spec);
            return;
        }

        $this-&gt;_templateLite-&gt;assign($spec, $value);
    }

    /**
     * 代入済みのすべての変数を削除します
     *
     * Zend_View に {@link assign()} やプロパティ
     * ({@link __get()}/{@link __set()}) で代入された変数をすべて削除します
     *
     * @return void
     */
    public function clearVars()
    {
        $this-&gt;_templateLite-&gt;clear_all_assign();
    }

    /**
     * テンプレートを処理し、結果を出力します
     *
     * @param string $name 処理するテンプレート
     * @return string 出力結果
     */
    public function render($name)
    {
        return $this-&gt;_templateLite-&gt;fetch($name);
    }
}
</pre>
<p>そのまんまですが。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.apecell.com/2007/10/19/id/18/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend Framework &#8211; Zend_Mailのドキュメントの間違い</title>
		<link>http://blog.apecell.com/2007/09/28/id/11</link>
		<comments>http://blog.apecell.com/2007/09/28/id/11#comments</comments>
		<pubDate>Thu, 27 Sep 2007 15:00:00 +0000</pubDate>
		<dc:creator>design</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Program]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[document]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://blog.apecell.com/1970/01/01/11</guid>
		<description><![CDATA[Zend_MailのSMTPによるメール送信で単一コネクションで複数のメールを送信する場合のマニュアルが間違えているので注意。確認したVersionと箇所は以下。
ZendFramework1.0.221.3. SMTP 接続による複数のメールの送信
「例 21.4. SMTP 雪像による複数のメールの送信」によると以下の様に書かれている。


require_once 'Zend/Mail.php';
$mail = new Zend_Mail();
// メッセージを作成します...
require_once 'Zend/Mail/Transport/Smtp.php';
$tr = new Zend_Mail_Transport_Smtp('mail.example.com');
Zend_Mail::setDefaultTransport($tr);
$tr-&#62;connect();
for ($i = 0; $i &#38;lt; 5; $i++) {
$mail-&#62;send();
}
$tr-&#62;disconnect();


が、上記だとZend_Mail_Transport_Smtpにconnectメソッドが無いのでエラーになる。
代わりにZend_Mail_Protocol_Smtpにあるのでそっちでコネクションを張ってZend_Mail_Transport_SmtpのsetConnectionメソッドでセットしてやる。

&#60;?php
$connection = new Zend_Mail_Protocol_Smtp($host, $port);
$connection-&#62;connect();
$connection-&#62;helo();

$tr = new Zend_Mail_Transport_Smtp;
$tr-&#62;setConnection($connection);

// 以下ループ処理
$mail = new Zend_Mail();

上記方法で1コネクションで複数のメール送信が出来る。
Zend_Mail_Transport_Smtpのデストラクタでdisconnectメドッソが呼ばれて自動的に接続解除されるので通常は問題無い。しかしSMTP接続がネットワーク障害で切れてしまった場合、disconnectの前に呼ばれるSMTPコマンドのQUITで例外が投げられるがデストラクタの例外は拾えなくてFatal Errorになってしまうので注意。
]]></description>
			<content:encoded><![CDATA[<p>Zend_MailのSMTPによるメール送信で単一コネクションで複数のメールを送信する場合のマニュアルが間違えているので注意。確認したVersionと箇所は以下。</p>
<p>ZendFramework1.0.2<br /><a href="http://framework.zend.com/manual/ja/zend.mail.multiple-emails.html" target="_blank">21.3. SMTP 接続による複数のメールの送信</a></p>
<p>「例 21.4. SMTP 雪像による複数のメールの送信」によると以下の様に書かれている。</p>
<blockquote>
<pre name="code" class="php">
require_once 'Zend/Mail.php';
$mail = new Zend_Mail();
// メッセージを作成します...
require_once 'Zend/Mail/Transport/Smtp.php';
$tr = new Zend_Mail_Transport_Smtp('mail.example.com');
Zend_Mail::setDefaultTransport($tr);
$tr-&gt;connect();
for ($i = 0; $i &amp;lt; 5; $i++) {
$mail-&gt;send();
}
$tr-&gt;disconnect();
</pre>
</blockquote>
<p>が、上記だとZend_Mail_Transport_Smtpにconnectメソッドが無いのでエラーになる。</p>
<p>代わりにZend_Mail_Protocol_Smtpにあるのでそっちでコネクションを張ってZend_Mail_Transport_SmtpのsetConnectionメソッドでセットしてやる。</p>
<pre name="code" class="php">
&lt;?php
$connection = new Zend_Mail_Protocol_Smtp($host, $port);
$connection-&gt;connect();
$connection-&gt;helo();

$tr = new Zend_Mail_Transport_Smtp;
$tr-&gt;setConnection($connection);

// 以下ループ処理
$mail = new Zend_Mail();
</pre>
<p>上記方法で1コネクションで複数のメール送信が出来る。</p>
<p>Zend_Mail_Transport_Smtpのデストラクタでdisconnectメドッソが呼ばれて自動的に接続解除されるので通常は問題無い。しかしSMTP接続がネットワーク障害で切れてしまった場合、disconnectの前に呼ばれるSMTPコマンドのQUITで例外が投げられるがデストラクタの例外は拾えなくてFatal Errorになってしまうので注意。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.apecell.com/2007/09/28/id/11/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend FrameworkのViewをSmartyに変更するには</title>
		<link>http://blog.apecell.com/2007/09/26/id/10</link>
		<comments>http://blog.apecell.com/2007/09/26/id/10#comments</comments>
		<pubDate>Tue, 25 Sep 2007 15:00:00 +0000</pubDate>
		<dc:creator>design</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Howto]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://blog.apecell.com/1970/01/01/10</guid>
		<description><![CDATA[
標準のZend Viewより使い慣れたSmartyを使いたかったので差し替えてみることに。
Zend Framework: Document &#8211; 35.3.2. 別のテンプレートシステムの使用の項目だけだとSmartyは呼び出せても実際どうやってControllerに組み込むの？となってしまう。
とりあえずControllerのViewを差し替えてみるかと思いZend_Controller_Actionを継承してinit()でSmartyを差し替えた。

&#60;?php
class Sample_Controller_Action extends Zend_Controller_Action {
    /**
     * @var Zend_Config
     */
    protected $_config;

    public function init() {
        // コンフィグの読み込み
        [...]]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>標準のZend Viewより使い慣れたSmartyを使いたかったので差し替えてみることに。</p>
<p><a href="http://framework.zend.com/manual/ja/zend.view.scripts.html#zend.view.scripts.templates" target="_blank">Zend Framework: Document &#8211; 35.3.2. 別のテンプレートシステムの使用</a>の項目だけだとSmartyは呼び出せても実際どうやってControllerに組み込むの？となってしまう。</p>
<p>とりあえずControllerのViewを差し替えてみるかと思いZend_Controller_Actionを継承してinit()でSmartyを差し替えた。</p>
<pre name="code" class="php">
&lt;?php
class Sample_Controller_Action extends Zend_Controller_Action {
    /**
     * @var Zend_Config
     */
    protected $_config;

    public function init() {
        // コンフィグの読み込み
        $this-&gt;_config = Zend_Registry::get('config');

        $extraParams = array(
            'compile_dir' =&gt; $config-&gt;smarty-&gt;compile_dir,
        );
        $this-&gt;view = new Sample_View_Smarty(null, $extraParams);
        $this-&gt;viewSuffix = 'tpl';
    }
}
</pre>
<p>が、上記だと上手くいかなかったわけで。</p>
<p>続いてActionHelperのViewRendererとしてSmartyを登録する方法で挑戦。</p>
<pre name="class" class="php">
<?php
$config = new Zend_Config_Ini('/path/to/config.ini', 'production');

$extraParams = array(
    'compile_dir' => $config->smarty->compile_dir,
);

// マニュアルに書かれているSmarty用View
$view = new Sample_View_Smarty(null, $extraParams);

$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
$viewRenderer->setViewBasePathSpec($config->smarty->template_dir)
    ->setViewScriptPathSpec(':controller/:action.:suffix')
    ->setViewScriptPathNoControllerSpec(':action.:suffix')
    ->setViewSuffix('tpl');

Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
</pre>
<p>上記方法で変更出来た。</p>
<p>これは継承したinit()では書かず、Controllerが呼ばれる前に書いた（Zend_Controller_Front::run()の前）。複数のテンプレートエンジン使い分ける事はほとんど無いと思われるのでこれで大丈夫かなと。</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.apecell.com/2007/09/26/id/10/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zend Frameworkで遊んでみる</title>
		<link>http://blog.apecell.com/2007/09/19/id/8</link>
		<comments>http://blog.apecell.com/2007/09/19/id/8#comments</comments>
		<pubDate>Tue, 18 Sep 2007 15:00:00 +0000</pubDate>
		<dc:creator>design</dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Program]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[zendframework]]></category>

		<guid isPermaLink="false">http://blog.apecell.com/1970/01/01/8</guid>
		<description><![CDATA[
自分用にコンディションシート的なものをZendFrameworkで作ろうと思い入れてみた。少し業務で使った事もあるけどSVNチェックアウト→OK!!な
状態だったので一からセットアップ。
一通りディレクトリ作ってphp.iniにパス通して
HelloWorld!!させてみる。問題無し。StaticなURLのルーティングを確かめる、以下が想定。
http://example.com/login
Controller =&#62; auth
Action =&#62; login

&#60;?php
$route = new
Zend_Controller_Router_Route_Static(
    'login',
     array('controller'=&#62; 'auth', 'action' =&#62;'login'));
$router-&#62;addRoute('login', $route);

これも問題無し。マニュアル通りだから問題無くて当然なんだけども。で、iniファイルにルーティング設定書こうと思って以下の様に書いてみた。
[production]
routes.login.type = "Zend_Controller_Router_Route_Static"
routes.login.route = "login"
routes.login.defaults.controller = "auth"
routes.login.defaults.action = "login"
読み込みはこんな感じ。

$config = new Zend_Config_Ini('../config/router.ini', 'production');
$router = new Zend_Controller_Router_Rewrite();
$router-&#62;addConfig($config, 'routes')

が、反映されてない。ルーターの値には同じものがセットされているというのに。
値が呼ばれてる所まで追ってみるかと思いつつ、先にガシガシコードに書いて後で精査してiniにしようとかなんとか。
そういえばPDT1.0がリリース。

]]></description>
			<content:encoded><![CDATA[<div class="section">
<p>自分用にコンディションシート的なものを<a href="http://framework.zend.com/" target="_blank">ZendFramework</a>で作ろうと思い入れてみた。少し業務で使った事もあるけどSVNチェックアウト→OK!!な</p>
<p>状態だったので一からセットアップ。</p>
<p>一通りディレクトリ作ってphp.iniにパス通して</p>
<p>HelloWorld!!させてみる。問題無し。StaticなURLのルーティングを確かめる、以下が想定。</p>
<pre>http://example.com/login
Controller =&gt; auth
Action =&gt; login</pre>
<pre name="code" class="php">
&lt;?php
$route = new
Zend_Controller_Router_Route_Static(
    'login',
     array('controller'=&gt; 'auth', 'action' =&gt;'login'));
$router-&gt;addRoute('login', $route);
</pre>
<p>これも問題無し。マニュアル通りだから問題無くて当然なんだけども。で、iniファイルにルーティング設定書こうと思って以下の様に書いてみた。</p>
<pre class="syntax-highlight"><span class="synSpecial">[production]</span>
<span class="synType">routes.login.type =</span> "Zend_Controller_Router_Route_Static"
<span class="synType">routes.login.route =</span> "login"
routes.login.defaults.controller = "auth"
<span class="synType">routes.login.defaults.action =</span> "login"</pre>
<p>読み込みはこんな感じ。</p>
<pre name="code" class="php">
$config = new Zend_Config_Ini('../config/router.ini', 'production');
$router = new Zend_Controller_Router_Rewrite();
$router-&gt;addConfig($config, 'routes')
</pre>
<p>が、反映されてない。ルーターの値には同じものがセットされているというのに。</p>
<p>値が呼ばれてる所まで追ってみるかと思いつつ、先にガシガシコードに書いて後で精査してiniにしようとかなんとか。</p>
<p>そういえばPDT1.0がリリース。</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.apecell.com/2007/09/19/id/8/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

