ホーム > Lithium

Lithium アーカイブ

参加していないあなたのためのPHP Matsuri PHP5.3のまとめ(2)

php_matsuri_lithium.png

前回の記事の続きです。

PHP 5.3+専用のフレームワークであるLithiumについて簡単にまとめます。

Lithium

Lithium: The Framework for People Who Hate Frameworks

このセッションでは”Lithium sucks.(Lithiumは最悪!)“という一文が出てきます。
Lithiumの紹介のセッションなのに、Lithiumは”最悪“なんです。

しかし、Nate Abeleさん曰く、問題ないそうで。
それは、

Because your framework sucks, too.(あなたのフレームワークも最悪だからね。)

とのこと。

こういった皮肉まじりのジョークが入り、楽しいセッションでした。
内容は以下の通りに進んで行きます。

  1. なぜ、フレームワークが最悪なのか
  2. 最近のLightweight Languageに適用されているデザインパターンはどうなのか
  3. Lihitumはそれをどう改善したのか
  4. Lithiumではどんなコードが書けるのか

それでは順に見ていきましょう。

なぜ、フレームワークが最悪なのか

フレームワーク利用者は皆思っていること。
それを適切に指摘します。

  • Code you will never use: あなたが使わないだろうコード
  • Complexity overhead: 複雑な処理によるオーバーヘッド
  • You didn’t write it: 自分で書いていないコード

フレームワークを使い始めたころはその便利さに感動します
しかし、この3つの項目はフレームワークを使い続けるにつれて、確かに気になってきます。

その結果、”フレームワークって要らないよね。“という極端な話になったり、ならなかったり。

Nate Abeleさんはコードも交えて説明してくれます。

function spam($emails) {
	$this->Email->replyTo = 'nigerian.prince@example.com';
	$this->Email->from = 'Desmond Etete <nigerian.prince@example.com>';
	$this->Email->template = 'mo_monies';
	$this->Email->sendAs = 'annoying_html';
	foreach ($emails as $email) {
		$this->Email->to = $email['address'];
		$this->Email->subject = 'Good to you news I have {$email['name']}';
		$this->Email->send();
	}
}
// $this->Emailばっかり...。Sucks!

まさにその通り!
これがCakePHPのコードです(この例は大げさだと思いますが)。
そして、フレームワーク利用者が気になるところでもあります

最近のLightweight Languageに適用されているデザインパターンはどうなのか

では、なぜこんなことになるのでしょうか。
それは、Java向けに作られたデザインパターンをLightweight Languageに適用したせいだとNate Abeleさんは言います。

デザインパターンは万能ではない。

つまり、

それぞれのデザインパターンは限られた条件下でその威力を発揮する。

ということです。

lithium_design_pattern.png

Lithiumはそれをどう改善したのか

LithiumではAspect-Oriented Designと言われるデザインパターンを使っています。
日本語ではアスペクト指向デザインと訳されます。


アスペクト指向プログラミング (AOP: Aspect Oriented Programming)は、オブジェクト指向ではうまく分離できない特徴(クラス間を横断 (cross-cutting) するような機能)を「アスペクト」とみなし、アスペクト記述言語をもちいて分離して記述することでプログラムに柔軟性をもたせようとする試み。

アスペクト指向プログラミング – Wikipediaより

例えば、

  • キャッシュ
  • ロギング
  • アクセスコントロール

これらは、処理の中心となるオブジェクトが知る必要がないんです
このようなコードを排除したいのです。

class User {
	public function create() {
		$logger = new Logger();
		$logger->write('Creating a new user...');
		$this->_doSomeInitialization();
		$this->_databaseConnection->doATransaction($this)->create();
		$logger->write('Finished creating user');
	}
}
$user = new User();
$user->create();
// ログを取るのに2回もwriteメソッドを呼ぶ必要がある。しかもcreateメソッドの中で!

確かに、こういった処理はコードを書く上で煩わしいものですよね。
本流の処理とはまったく関係ない処理が、途中に入るためにとてもコードが見づらくなる

さらにこれらの問題を解決するために関数型プログラミングも取り入れています。
これが前回説明した無名関数(lambda式)に繋がります。

これを取り入れることで”参照透過性“を高めることが出来ると言います。

Lithiumでは以下の機能を全てアダプタとして提供しています。

  • Auth
  • Cache
  • Catalog
  • Connections
  • Logger
  • Session

アダプタとして提供されるということは、結びつきが少なくそれぞれのクラスごとにカスタマイズが効くということ
以下のコード例が紹介されます。

use lithium\security\Auth;
Auth::config(
	array(
		'customer' => array(
			'adapter' => 'Form',
			'model' => 'Customer',
			'fields' => array('email', 'password')
		)
	));
use lithium\storage\Cache;
Cache::config(
	array(
		'local' => array('adapter' => 'Apc'),
		'distributed' => array(
			'adapter' => 'Memcached',
			'servers' => array('127.0.0.1', 11211),
		),
		'default' => array('adapter' => 'File')
	));
use lithium\data\Connections;
Connections::config(
	array(
		'old' => array(
			'type' => 'database',
			'adapter' => 'MySql',
			'user' => 'bobby_tables',
			'password' => '******',
			'database' => 'my_app' ),
		'new' => array(
			'type' => 'http',
			'adapter' => 'CouchDb',
			'database' => 'my_app' )
	));

キャッシュを複数環境で運用したい場合は、

use lithium\storage\Cache;
Cache::config(
	array(
		'default' => array(
			'development' => array(
				'adapter' => 'Apc'
			),
			'production' => array(
				'adapter' => 'Memcached',
				'servers' => array('127.0.0.1', 11211)
			)
	)
));

こういった書き方が出来ます。

lithium_adapter1.png

lithium_adapter_2.png

確かにフレキシブルで書きやすそうですね。

Lithiumではどんなコードが書けるのか

コード例がいくつか紹介されます。
まずはキャッシュとロギング。

lithium_caching_and_logging.png

use lithium\analysis\Logger;
Post::applyFilter('find',
	function($self, $params, $chain) {
		// Generate the log message
		$conditions = $params['options']['conditions'];
		$message = 'Post query with constraint ' . var_export($conditions, true);
		Logger::write('info', $message);
		return $chain->next($self, $params, $chain);
	});

次にモデル。

lithium_databases.png

<?php
	$post = Post::create(array(
		'title' => 'Forget the words and sing along',
		'body' => 'Everything you know is wrong' )); $post->save(); $post = Post::find($id);
?>
<h2><?=$post->title; ?></h2>
<p><?=$post->body; ?></p>

最後に外部ライブラリの読み込み。

/* add the trunk */
Libraries::add('Zend', array(
	'prefix' => 'Zend_',
	'includePath' => '/htdocs/libraries/Zend/trunk/library',
	'bootstrap' => 'Loader/Autoloader.php',
	'loader' => array('Zend_Loader_Autoloader', 'autoload'),
	'transform' => function($class) { return str_replace('_', '/', $class) . '.php'; }
));
// Note that 'path' can be dropped if trunk/library/Zend is placed
// directly into your /libraries directory. 

/* add the incubator */
Libraries::add('Zend_Incubator', array(
	'prefix' => 'Zend_',
	'includePath' => '/htdocs/libraries/Zend/incubator/library',
	'transform' => function($class) { return str_replace('_', '/', $class) . '.php'; }
));

簡単ですがLithiumのまとめはここまでです。
Lithiumを使ってアプリケーションを書いたことがないので、理解が浅い部分があります
そのため、Nate Abeleさんの話を簡単にまとめてみました。

もし、Lithiumの情報に日本語でアクセスしたい場合は@yandoさんのブログを見てください。

Lithiumのアップデート毎に翻訳を書いてくれているので、とても参考になります。

内部処理について知りたい場合は、@shin1x1さんがLithiumのフィルタについてまとめてくれています。

また、途中に”Relational databases coming soon“とあるのですが、MySQLのアダプタは公式から出ています。
PostgreSQLのアダプタ@kaz_29さんがPHP Matsuriのハッカソンで開発してくれました。

PHP Matsuriの大きな成果の一つですね。

これからはCakePHPだけでなく、Lithiumも触ってみたいと思います。
ちょくちょくLithiumネタも書いていくので、1-byte.jpもよろしくお願いします。

ホーム > Lithium

スポンサードリンク
書いている人
つぶやき
RSS 気になるニュース
過去の記事

ページの上部に戻る