Home

日記
3/19夕方〜3/20朝まで一部でDBエラーが出ていましたEdit

サーバーの各種モジュールのアップデートを行った際に、mysqlがテンポラリディレクトリとして使用していた/dev/shm以下にアクセスできなくなり、上記ディレクトリにテンポラリテーブルを作成するようなqueryのみエラーになるという症状で、気づくのが遅れました。申し訳ありません。

Published At2006-03-20 00:00Updated At2006-03-20 00:00

日記
腰が痛いEdit

昨日の昼に買物から帰ってソファに腰を下ろしたら、突然腰に痛みが走った。なんかいかにもやばそうな痛み。ちょっとでも腰に負担をかけたらかなりの痛みが走る。やばいなーと思いつつできるだけ腰に負担をかけないように1日を過ごしたんだけど、翌朝起きてもまだ痛い。今日の朝一番で病院に行こうと思っていたんだけど、近所の病院はゲロ混みだったんでひとまずやめて、会社に来てみたところ、椅子に座っているとだんだん痛みの範囲が広がってきたんで、これはまずいと午後一で病院に行った。で、結局診断としては、背骨の一番下の腰骨と接続するあたりの軟骨が、微妙に接触しているのが原因だと思われるけれども、特にひどい状態ではないから一週間くらいで治るでしょう、とのこと。それ以外は特に問題はないらしい。ヘルニアとかひどい方向を想像していたんで、ほっとした。痛いだけで済むならいいや。一応痛み止めを出してもらって、電気治療も受けてきた(結構効果があって、受けた後は痛みがずいぶん和らいだ)。

Published At2006-03-20 00:00Updated At2006-03-20 00:00

日記
PHP5への道Edit

PHP5への移行を決意したわけだが、早速気が重くなってきた。

ひとまずローカルWindows環境をPHP5に入れ替えてみたんだけど、パスとかは正しいにもかかわらず、指定したextensionのDLLが見つからないと言われるし、PEARも標準状態で素直にインストールされてくれない。単に動かすだけでも結構トラブルが多そう。こういうトラブルは、多分*nix系では出ないとは思うんだけど、印象が良くないなー。

さらに、手持ちのアプリケーションを動かそうとしたところ、各種エラー(主にE_NOTICEやE_STRICT)が出るのは覚悟していたけれども、そのエラーメッセージが訳分からない。エラーが出ているところとは全然違うファイル+行を差したエラーメッセージ(指定された場所にはそんなエラー発生源はない)が表示されたりする。これはいったい何が原因なんだろうなー。→E_STRICTをトラップしないエラーハンドラーが原因だった。

あと、予想していたよりも、思いのほかいろんなエラーが出てくるなー。クラスのメソッドの中で必要に応じて外部クラスをrequire_onceで読み込んだりすると、nested classとか言われちゃうのか。あとis_aとかもdeprecatedらしいし。どうせ移行するなら、自分のコード部分はE_STRICTレベルまできっちり対応しておきたいけど、この様子だとPHP4との互換性を保ったままPHP5に移行するなんてのは不可能っぽいな。全面的にPHP5に移行するしかなさそげ。

PHP4のコードがだいたいそのまま動くように作られているらしいと聞いて、もうちょっと互換性が高いことを期待していたんだけど、それはあくまでもPHP4のコードをだましだまし動かすこともできるよ、ってレベルだね。PHP5できちんと動くコードを書こうと思ったら、PHP4との互換性はとても保てない(クラスライブラリ的なものは特に)。

まあそれでも、今までPHP4だから妥協していた部分がいろいろきれいに書けるようになるし、何よりエラーハンドリングがまともに書けるようになるし、頑張ってPHP5に移行していこう。思ったよりもずいぶんつらそうだけど。

Published At2006-03-20 00:00Updated At2006-03-20 00:00

日記
Zend Frameworkをどう使うかEdit

PHP5への移行を決意したのはZend Frameworkの存在も大きいわけだが、Zend Frameworkがどのくらいで実用レベルに達するのか、現時点では全然見通しが立っていない。少なくとも半年程度は待たなければならないんじゃないかと思われるんで、ここ一、二ヶ月程度のスパンではZend Frameworkの存在を意識しつつも、Zend Frameworkにあまり依存しないようなアプローチでPHP5対応を行う必要があるだろう。

というわけで、いつのまにかPreview 0.1.2まで出ていたZend Frameworkを真面目にチェック。フレームワークのコアとなるControllerとViewまわりがどんな感じなのかについては、php architecttutorialが一番わかりやすいドキュメントだろう。チュートリアルなんで内部構造にはほとんど触れず、使い方のレベルの説明だけど。

で、内部構造の方は、マニュアルのControllerパートとソースを読む限りでは、結構柔軟に差し替え可能な模様。

$controller = Zend_Controller_Front::getInstance();
$controller->setRouter(new MyRouter());
$controller->setDispatcher(new MyDispatcher());
$controller->setControllerDirectory($controllerDirectory);

みたいな感じで、Router(URIからAction名を解決する)やDispatcher(Routerで解決されたAction名から、Actionオブジェクトを生成し、実行する)は差し替えることができる。

あと、

$controller->registerPlugin(new MyPlugin());

とかやると、プラグインが登録できるけど、マニュアルにはプラグインに関する記述がない。ただ、Zend_Controller_Front::dispatchと、Zend_Controller_Plugin_Interfaceを見ればだいたい挙動がわかる。各プラグインには、$controller->dispatch()中に発生する下記のイベントに対応するハンドラーメソッドを書いておき、対応したハンドラーがあればそのプラグインが実行される(なければスルー)、って感じだろう。

  • routeStartup() - $controller->getRouter()->route()前。1リクエストごとの前処理用プラグインで使うんだろう。認証とかもこの辺にかませるのが基本かな。
  • routeShutdown($action) - $controller->getRouter()->route()後。デフォルトのrouteで解決したActionを、後付けで書き換えたりセットアップ処理を追加したりするときに使うのかな?
  • $action = dispatchLoopStartup($action) - Actionのdispatch処理は、戻り値として次のActionを返すことにより、複数のActionの連鎖実行(dispatchLoop)できる。そのdispatchLoop前。最初に実行するActionが解決したあとの前処理用か。
  • $action = preDispatch($action) - Actionのdispatch前。dispatchLoop内で実行される一つのActionごとに呼ばれる。最初に実行するかどうかに限らず、特定のActionに対する前処理。
  • $action = postDispatch($action) - Actionのdispatch後。dispatchLoop内で実行される一つのActionごとに呼ばれる。preDispatchに対して、特定のActionに対する後処理用かと思いきや、この段階では$actionは次のActionに書き換えられているはずだから、plugin内で状態を保持していない限りは、次のActionの前処理と大して変わらないことしかできないな。ってことは、特定のActionに対する前処理後処理を書きたかったら、一つのプラグインでpreDispatchとpostDispatchを処理しつつ、プラグイン側で状態を保持する必要がありそう。
  • dispatchLoopShutdown() - dispatchLoop後。全体の後処理。ただし、途中でdieしたりするパターンは(少なくとも正常ルートでは)ないんだろうか? あったら使える状況は限られてしまいそうだけど。

基本的な処理パターンを、Controller、Router、Dispatcher、各Actionに記述しつつ、パターンをまたがった処理はプラグインで書いていく感じかな。なんかプラグインって名前がちょっと違和感を感じるけれども、使い勝手と柔軟性はなかなか高そう。認証とかのクラスを基本的な処理パターンに密結合させると、一気に柔軟性が失われたりするものだけど、そのへんはプラグインに出してしまおうってことなんだろう。

ただ、そうなると認証とかの状態維持はZend::registerあたりを使ってねって話なのかなー。あれはちょっと汎用的な入れ物すぎるけど、$controllerが保持するくらいだったらZend::registerでも大して変わらないしなー。かといってActionのインスタンスは実行する瞬間しか存在しないから、Actionをまたがった入れ物としては使えないし。プラグインが状態を保持するというアプローチはありかもしれないけど、プラグインのインスタンスへの直接アクセス方法がないから、いまいち使い勝手が良くない気もする。

というところで疲れてきたので休憩。

Published At2006-03-21 00:00Updated At2006-03-21 00:00

日記
Zend Frameworkをどう使うか その2Edit

さて、次はZend_View。Controllerが比較的薄くて差し替え可能なクラスを積み重ねている感じだったんで、Viewも似たような感じかなーと思ったら、Viewの方はZend_View自体が結構機能を持っているな。

基本機能としては、

$view = new Zend_View();
$view->setScriptPath($templateDir);
$view->assign('foo', 'FOO VALUE');
echo $view->render($templateFile);

みたいな感じか。ただしassignの代わりに__setと__getをつかって、

$view->foo = 'FOO VALUE';

みたいな記法もサポートしている(内部的にはassignするのと同じく、$this->_varsにセットされる)し、連想配列とかstdclassのプロパティとかを使ってassignしてもOK。まあこの辺はPHPのテンプレート展開処理で使われるいろんな方法は一通りサポートって感じか。

で、標準のテンプレート展開処理(=PHPのコードをincludeするだけ)では、

<?php echo $this->foo; ?>

で、セットした'FOO VALUE'が出力される(エスケープされない)。

で、escapeは特別なメソッドとして用意されていて、デフォルトでは

$this->_escape = 'htmlspecialchars';

というコールバックメソッドが登録されていて、

<?php echo $this->escape($this->foo); ?>

とすると、$this->escape()の実体としてhtmlspecialcharsが呼ばれて、エスケープ出力される。これは差し替え可能なコールバックメソッドなんで、

$view->setEscape('another_escape_function');

とかすれば、$this->escape()で別のエスケープ処理が使われるようになる。けど、なんでescapeを特別扱いしているのか、いまいち理由が分からない。

というのは、Zend_Viewでは汎用的な機能拡張方法として、helperってプラグインみたいな口が用意されていて、addHelperPathとかで指定したhelper用ディレクトリに、独自のhelperクラス(たとえばMyHelper.phpとか)を用意しておけば、 $view->myHelper()なんて感じでその処理を呼び出すことができるようになっている。escapeもそれで十分表現できるんだし、それでいいんじゃないのかなー(ただ、現状のZend_View_Abstract::_loadClassでthrow new Zend_View_Exceptionしている場所がおかしいんで、helperの検索が正しく働かない気がする。と思ったらMLで報告されていた)。

ちなみに標準のhelperとしては、FormButtonとか主にフォーム部品用のhelperが用意されている模様。ZFormとは違って、こっちはちゃんと出力は必要に応じてエスケープされるようになってるな。

あと、出力結果全体にかかるfilterもセットできるようになっていて、helperと同じようにaddFilterPathとかでfilter用ディレクトリをセットしてから、$view->addFilter('filter_name')とかすると、filterが追加される。filterは複数セットすることができ、renderの最後でまとめてかけられるようになっている。

と書きながらZend_View_Abstract::renderを読んでいたら、単純にレンダリングしているだけでなく、なんか変なスタックを積んでいるな。これって特にマニュアルには記述がないみたいだけど、renderの中でさらにrenderできるようになっているっぽい。

$view->render('foo.php');

とかやっておいて、foo.phpの中で、

<?php $this->render('bar.php'); ?>
<?php $this->render('baz.php'); ?>

とかやった場合に、正しくレンダリングされる(最初のfoo.phpのrenderが終わった段階で、まとめて出力が返される)ようになっている(気がする。動作確認してないけど)。一応テンプレートを複数のパーツに分割して管理することを意識しているのね。

まあ標準のZend_View(=テンプレートはViewオブジェクトのスコープで動作するPHPのコードをそのまま書く)で使う場合は、それはそれで結構便利そう。ただ、今まで他のテンプレートエンジン(というかSmarty)を使っていた人はどうするべきだろう。いくらZend_Viewがそれなりに高機能で拡張性があっても、今更<?php echo $this->escape($this->foo); ?>なんて記述はしたくないなー。

といったところで、また調査に戻る。

Published At2006-03-21 00:00Updated At2006-03-21 00:00

日記
Zend Frameworkをどう使うか その3Edit

Zend Framework(あるいはZend_View)と既存のテンプレートエンジンとの兼ね合いについては、MLのTemplate system, form handling and time scheduleから始まるスレッドを一読しておくといい。

Zend Frameworkのアプローチとしては、マニュアルに例として掲載されているような外部テンプレートシステムとの連携を基本と考えているのだろう。最初このマニュアルの例が何を意味しているのかよく分からなかったが、これはZend_Viewからrenderで呼び出されるスクリプト内で、PHPLIBスタイルのテンプレートを利用している、という意味のようだ。Zend_Viewからrenderで呼び出されるコードはテンプレートではなく、あくまでもHTML出力用のPHPコードであり、そこでさらに外部テンプレートシステムを使って出力するコードを書け、ということだ。さすがにその書き方はきっついなーと思わないでもないが、Zend Frameworkの構成要素自体は外部テンプレートシステムから独立するというポリシーを維持するためには、それなりにまっとうなアプローチだろう。

あと、SmartyのサイトからもリンクされているZend Framework: Using Smarty as template engineという記事で紹介されているアプローチがある。これは、SmartyのオブジェクトはZend::registerに突っ込んでおいて、Actionで直接Smartyを使ってHTMLを出力してしまい、Zend_Viewなんか使わない、というものになっている。この記事の作者は、

As you can see Smarty integration with Zend Framework is very simple task. Zend_View has ability to use your own filters and helper functions, but with Smarty you don’t need them because Smarty has its own plugins, filters, modifiers. Just forget about Zend_View and use best template engine for PHP in the world!

とまとめている。機能がかぶっているZend_Viewなんかのことは忘れて、Smartyをそのまま使った方が幸せになれるよ、って感じ。Smartyオブジェクトの置き場所がZend::registryってあたりはいまいちだし、Zend Framework全体のアプローチともきれいにかみ合わないけれども、機能としては問題ないし無駄も少なく実際的なアプローチだよな。

ちなみに上記記事のコメント欄では、Zend_View_Abstractを継承して、Smarty用のViewクラスを作ってそれを使うという、クラスライブラリ的にはかなりまっとうそうなアプローチを紹介している人がいるけれども、この記事の作者は、

I tried to create something similar but I don’t see advantages of this approach. (中略)You’ve extended Zend_View_Abstract but you don’t use almost all its functionality. I don’t think this is a good object-oriented practice - to extend but not to use methods of base class.

と答えている。確かにZend_View_Abstractを継承しているけれども、Zend_View_Abstractの機能なんてほとんど使ってないじゃん、そんなんじゃ継承している意味がないじゃん、って感じか。根性入れて、Zend_ViewのhelperとかfilterとかをSmartyのpluginとかと互換モードで動かすくらい気合いの入ったSmarty用Viewを書かないと、ほとんどの機能は互換性がないからなー。表面上のassign、render周りのインターフェースが同じになるだけでもそれなりに意味はあるとは思うけど、そんなのに大した意味はないと切り捨てる意見もわからないでもない。

ちなみに現状では実用的ではないけれども、アプローチとして一番面白かったのは、Smarty Plugin for viewというMLの投稿。これは、SmartyによるレンダリングをZend_Viewのフィルターとして実行してみよう、というもの。Zend_Viewはそのまま使い、そこでふつうにSmarty用のテンプレートファイルをrenderする。もちろんZend_ViewはSmarty用のテンプレート言語は知らないから、そのままスルーする。そしてrender後のフィルター処理でSmartyのレンダリング処理が行われる。残念なことにフィルターにはZend_Viewにassignされた値が渡されないので、現状では実用的ではないけれども(テンプレート変数が渡らないんじゃレンダリングしても意味がない)、何とかその辺を解決することができればなー。

そういやさっきのMLスレッドの最後の方に、

<disclaimer>Don't quote me and blame me if I'm wrong</disclaimer>

We are aiming to have something shippable in the 2nd half of 2006. However, this will very much depend on how the development goes and if we have enough proof points to be confident that it's in good shape design wise.

ってのがあった。2nd half of 2006って2006年下半期ってことだよね。要は2006年12月いっぱいまでってことだよね。まあそんな感じかなーとは思っていたけど、やっぱり遅そうだなー。

Published At2006-03-21 00:00Updated At2006-03-21 00:00

日記
Zend Frameworkをどう使うか その4Edit

Zend Frameworkの感触だけ確かめるつもりだったんだけど、思ったよりも深追いしすぎている気がするな。でもまあいずれやらなきゃならないことだから、今やっておいても無駄にはなるまい。

で、さすがにそろそろコードを追うだけじゃなくて、実際に動かしてみようってことで、サンプルを作って動かしてみた。ただ、標準のmod_rewriteを前提としたRouterだと気軽にテストできないんで、

<?php
Zend::loadInterface('Zend_Controller_Router_Interface');
class MyRouter implements Zend_Controller_Router_Interface
{
public function route(Zend_Controller_Dispatcher_Interface $dispatcher)
{
$path = $_SERVER['PATH_INFO'];
$path = explode('/', trim($path, '/'));
$controller = $path[0];
$action     = isset($path[1]) ? $path[1] : null;
if (!strlen($controller)) {
$controller = 'index';
$action = 'index';
}
$params = array();
for ($i=2; $i<sizeof($path); $i=$i+2) {
$params[$path[$i]] = isset($path[$i+1]) ? $path[$i+1] : null;
}
$actionObj = new Zend_Controller_Dispatcher_Token($controller, $action, $params);
if (!$dispatcher->isDispatchable($actionObj)) {
throw new Zend_Controller_Router_Exception('Request could not be mapped to a route.');
} else {
return $actionObj;
}
}
}
?>

みたいにPATH_INFOからActionを解決するようにしたRouter(上記ソースは、REQUEST_URIの代わりにPATH_INFOを使うようにした以外は、Zend_Controller_Routerとほとんど同じ)を用意しておいて、

Zend::loadClass('Zend_Controller_Front');
$controller = Zend_Controller_Front::getInstance();
$controller->setRouter(new MyRouter());
$controller->setControllerDirectory('/path/to/app');
$controller->dispatch();

という風にRouterを差し替えて動かす。すると、

http://example.com/path/to/sample.php/[CONTROLLER]/[ACTION]

なんて感じでアクセスできるようになる。あるいはaction=[CONTROLLER]/[ACTION]とか、module=[CONTROLLER]&action=[ACTION]とかのQUERY_STRINGから解決する方がテスト用にはいいのかな。

まあそんな風にして動作させたところ、思ったような感じで動作してくれているんで、今までソースとマニュアルを読んだだけで理解してきたことは、特に大きくは外してはいない模様。

というわけで、しばらく実際にいろいろ動かして試してみることにする。

Published At2006-03-22 00:00Updated At2006-03-22 00:00

日記
[Zend Framework: Zend Frameworkをどう使うか その5Edit

プラグインが考えたとおりに動くかどうかテスト。

<?php
Zend::loadClass('Zend_Controller_Plugin_Abstract');
class AuthPlugin extends Zend_Controller_Plugin_Abstract
{
public function routeShutdown($action)
{
if (!session_id()) {session_start();}
if ($this->_isLogin()) {return $action;}
$action->setControllerName('login');
$action->setActionName('index');
return $action;
}
private function _isLogin()
{
if (isset($_SESSION['login'])) {return true;}
if (($_POST['id'] == 'testid') && ($_POST['pwd'] == 'testpwd')) {
$_SESSION['login'] = true;
return true;
}
return false;
}
}
?>

な感じで認証プラグインもどきを作る。routeStartupではActionが書き換えられないんで、routeShutdownの方をフック。上のコードでは、元のActionを活かして、Controller名とAction名を認証ページに書き換えているけど、こうやって全然違うActionにマップし直す場合は、

return new Zend_Controller_Dispatcher_Token([CONTROLLER], [ACTION]);

という風に、本当はToken自体を作り直した方がいいよね。でもまあそのままにしておこう。で、FrontControllerを作るときに、

Zend::loadClass('Zend_Controller_Front');
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('/path/to/controllers');
$controller->registerPlugin(new AuthPlugin());
$controller->dispatch();

なんて感じで、プラグインを登録してからdispatchする。すると、どのActionが指定された場合も、必ず事前にAuthPluginが呼ばれるようになり、認証に通っていなかったら強制的にActionはLoginController::indexActionに差し替えられるようになる。LoginControllerは

Zend::loadClass('Zend_Controller_Action');
class LoginController extends Zend_Controller_Action
{
public function indexAction()
{
Zend::loadClass('Zend_View');
$view = new Zend_View();
$view->setScriptPath('/path/to/views');
echo $view->render('login.php');
}
public function noRouteAction()
{
echo get_class($this) . '-&gt;' . 'noRouteAction';
var_dump($this->_getAllParams());
}
}

な感じで、login.phpは、

<form method="post">
ID: <input type="text" name="id" /><br />
Password: <input type="password" name="pwd" /><br />
<input type="submit" value="login" />
</form>

な感じ。これでプラグインを使った認証処理が実現できる。ただ、ここでは単に認証を通すだけだけれども、ふつうのアプリケーションならば認証されたユーザー固有の状態を保持・参照できるようにする必要がある。そういう機能を受け持つものはZend Frameworkには見あたらないっぽいんで、自前でセッションにユーザークラスとかを入れておくとか、Zend::registryあたりで持ち回すとかする必要があるだろう。

Published At2006-03-22 00:00Updated At2006-03-22 00:00

日記
Zend Frameworkをどう使うか その6Edit

さて続いては、一番いじりがいがあって、しかも今後インターフェースが変わりそうな気配が濃厚なZend_View周りをいじってみよう。まずは、 Zend Frameworkをどう使うか その2で予想した、Zend_View::render内で$this->renderした場合に、正しくレンダリングされるかどうかのテスト。

$view = new Zend_View();
$view->setScriptPath('/path/to/views');
$view->foo = 'FOO';
$view->render('index.php');

なんて感じで呼び出し、index.phpの方で、

<p>header</p>
<?php $this->render('body.php'); ?>
<p>footer</p>

なんて書いて、body.phpでは、

<p>foo value is <?php echo $this->escape($this->foo); ?></p>

と書くと、

<p>header</p>
<p>foo value is FOO</p>
<p>footer</p>

と出力が得られた。ちゃんと入れ子のrenderも実行してくれるみたいだね。ちなみにindex.phpでは、

<p>header</p>
<?php echo $this->render('body.php'); ?>
<p>footer</p>

とrenderの戻り値をechoするようにしてもしなくても結果は同じ。というのは、Zend_View::renderは入れ子の中で呼ばれた場合は、出力結果を文字列で返さず、親のrenderでob_startされた出力バッファリングにくっつけて出力し、親のrenderが終わった段階でまとめて結果を返すようになっているから。というわけで利用者レベルではechoをつけてもつけなくてもいいわけだけど、開発者はどっちの記述法を基本にするつもりなんだろうな。まあ大した問題ではないけど。

ちなみに上記サンプルにもあるとおり、Viewにセットした値は入れ子の中のrenderで呼ばれたテンプレート(PHPコード)の中でもふつうに使える。というか、renderが入れ子になっていても、呼び出すViewオブジェクト自体は変わらない=renderされるPHPコードのスコープは変わらないから、まあ当たり前。もちろん、

<?php $view = new Zend_View(); $view->render('foo.php'); ?>

とか明示的に別のViewオブジェクトを作ったら、別のスコープでレンダリングされるけどね。パーツをレンダリングするときに、使える(見える)値を制限したい場合は、そういう使い方もあるかも。

Published At2006-03-22 00:00Updated At2006-03-22 00:00

日記
Zend Frameworkをどう使うか その7Edit

ひとまず、その他のテンプレートエンジンを使わず、お作法に則ってZend_Viewを使うアプローチについて考えてみる。Zend Frameworkの設計は筋がいいんで、アプリケーションの処理の流れに関するコードはきれいに記述できるし、PHP言語自体テンプレート記法みたいなもんだと考えれば、HTMLテンプレート(Zend_Viewでrenderするファイル)もきちんとロジックと分離して管理できる。

けど、やっぱり<?php echo $this->escape($this->foo); ?>という記法は我慢できない。書籍でも上記のような記法は我慢できなくて、ショートタグを有効にして、<?=h($foo) ?>*1みたいな記述を採用したし、ショートタグが使えない場合の代替手段としても、<?php eh($foo); ?>*2を採用した。単にテンプレート変数を展開(エスケープ付き)するだけなら、この程度の入力しやすさ&可読性の良さを期待したい。

では、どうやってZend_Viewをベースに上記のような入力しやすさ&可読性の良さを獲得するか。アプローチはいろいろ考えつくけれども、ひとまずZend_Viewを拡張するまっとうな手段であるhelperを使って書いてみることにする。

といっても、helperは単にZend_Viewの中から$this->[helperName]で呼び出すことができるという以上の機能は持ち合わせていないんで、escapeのショートカット関数を定義するくらいにしか使えそうにない。

class Zend_View_Helper_E
{
public function E($value)
{
return htmlspecialchars($value);
}
}

なんてhelperを書いて、$view->setHelperPath('/path/to/helpers')してから、

<?php echo $this->e($this->foo); ?>

する程度が関の山か。ちょっとは短くなったけど、可読性が高いとはとても言えない。あるいは、

class Zend_View_Helper_E
{
public function E($value)
{
echo htmlspecialchars($value);
}
}

としちゃって、

<?php $this->e($this->foo); ?>

とすればもっと短くなるけど、これだとテンプレート変数を出力しているように見えなくなっちゃうんで、短くなっても可読性は落ちてる気がするしなー。まあ慣れればこれでもいいかもしれないけど。

と試してみてやっぱり、Zend_Viewがescapeを特別扱いしている意味が感じられないよなーと再確認した。escape用のhelperを標準で用意しておけばそれでいいじゃん。helperの書き換えもaddHelperPathして上書きすればいいわけだし*3。Zend_Viewがescapeを特別扱いしているのは、「escape重要!」というポリシーを知らしめるためとか、helperよりも汎用性の低い実装にすることで多少のパフォーマンス上の利点があること、くらいしか思いつかない。

*1 hはhtmlspecialchars関数へのショートカット

*2 ehはecho htmlspecialchars相当の機能へのショートカット

*3 後からaddHelperPathされたパスが優先されるんで、同名の独自のhelperを用意すれば上書きできる

Published At2006-03-22 00:00Updated At2006-03-22 00:00