2.include_pathの技法
相対パスを使ってincludeやrequireを実行するようにしていると、「includeが書いてあるファイルを別な階層のディレクトリからincludeしようとする際、エラーになってしまう」ということがあります。フレームワークでは複数のディレクトリから、いくつかのファイルを読み込むことになるので、このあたりが悩ましいのですが、CakePHPではinclude_pathを後から設定することでこの問題を解決しています。
Cakeは単に圧縮ファイルを展開して配置するだけで、開発が始められるように設計されています。しかし開発が終わって実運用する際に、「webroot」フォルダだけをWEBに公開する、という配置にすることも考慮されています。サーバのDocumentRootの変更権限を持っている場合には、CakePHPのディレクトリ構成を変えずに、単にDocumentRootの位置を「app/webroot」ディレクトリに設定するだけでCakePHPアプリケーションを動かすことができます。これがいちばん簡単な公開用のセッティングです。
しかし、さらに高度に設定を変える方法もあります。関係するパラメータは、ROOT、APP_DIR、CAKE_CORE_INCLUDE_PATHです。
- Cake本体
- 自分の作成したプロジェクトファイル
- 公開する「webroot」ディレクトリ
これで、
- Cake本体
- 自分の作成したプロジェクトファイル
- 公開する「webroot」ディレクトリ
の3つが決まることになります。
WEBROOT_DIR:WEBROOTに相当するディレクトリの名前(デフォルトは「webroot」)。WWW_ROOT:WEBROOT_DIRがある場所へのパスもあります。
「mod_rewrite」が効いていたり、「app/webroot/index.php」に直接たどりついたりした場合には、自動的に上の2つの定数の値が設定されます(「app/webroot/index.php」のファイルがある位置が、
WWW_ROOT+WEBROOT_DIRということです)。しかし、「mod_rewrite」が効かない状態でcakeの親フォルダからアクセスさせ、webrootの位置も変更したい場合には、この値を自分で設定する必要があります(現在の「index.php」の設定は、単純にCakePHPプロジェクトを展開した場合に正しく動くようなパス設定になっています)。index.php
CakePHPの内部を理解するために、index.phpのコードを少したどってみます。
if (!defined('CORE_PATH')) { if (function_exists('ini_set')) { ini_set('include_path', ini_get('include_path') .PATH_SEPARATOR.CAKE_CORE_INCLUDE_PATH .PATH_SEPARATOR.ROOT.DS.APP_DIR.DS); define('APP_PATH', null); define('CORE_PATH', null); } else { define('APP_PATH', ROOT.DS.APP_DIR.DS); define('CORE_PATH', CAKE_CORE_INCLUDE_PATH.DS); } } require CORE_PATH.'cake'.DS.'bootstrap.php';
ここで、設定オプションが追加できることを確認してから、include_pathの中に、CakeのCAKE_CORE_INCLUDE_PATHのパスとROOT+APP_DIRのパスを追加しています(PATH_SEPARATORは、Windowsの場合はセミコロンになることに注意)。さらに、APP_PATHとCORE_PATHという定数はnullに設定されるので、これは存在していないことと同じになります。
ですから、次の
require CORE_PATH.'cake'.DS.'bootstrap.php';
という部分は、
require 'cake/bootstrap.php';
として呼んでいるのと同じことになります。include_pathが使えない環境であれば、この部分は、
require 'Cakeのcoreがインストールされたパス/cake/bootstrap.php';
として実行されます。独自にCAKEファイルをrequireするときには、APP_PATHやCORE_PATHの定数を含めておくようにしましょう。そうすれば、ディレクトリの階層を考える必要がありません。しかし、たいていの場合はnullになっており、実際のパスはinclude_pathに記述されている場合がほとんどでしょう。
3.PHPのバージョンによる使い分け
CakePHPはPHP4とPHP5をサポートするフレームワークです。そのため、PHP5の環境で開発し、クライアントの要望に応じて、PHP4のサーバにしたり、PHP5で運用したりと使い分けることが可能です。しかし、PHP4とPHP5でどんな違いがあるのかを開発者が把握している必要があります。CakePHPフレームワークにかかわってくるPHP4とPHP5の大きな違いは、
- PHP5のデフォルトでは、オブジェクトのコピー方法が参照渡しになった
- PHP4では、コンストラクタ名はクラス名と同じ関数。PHP5では
__constructというメソッドが優先される - メンバーとメソッドのオーバーロード
などがあります。CakePHPはこの3つの違いを吸収するために次のような処理を行っています。
- 「model_php4.php」と「model_php5.php」という2つのModelクラスを準備し、model.php内の下記のコードで読み分ける。
- すべてのクラスを
object.phpから派生させます。そして、Objectクラスのコンストラクタで下記のような作業を行います。 - CakePHPのモデルには、
findAllByフィールド名($value);というマジック関数があります。これは、例えばあるusersテーブルの中に、title、name、addressがある場合には、
if (phpversion() < 5) { require(LIBS.'model'.DS.'model_php4.php'); if (function_exists("overload")) { overload("Model"); } } else { require(LIBS.'model'.DS.'model_php5.php'); }
function Object() { $args = func_get_args(); if (method_exists($this, '__destruct')) { register_shutdown_function (array(&$this, '__destruct')); } call_user_func_array(array(&$this, '__construct'), $args); }
register_shutdown_function()は、スクリプト処理が完了した際に実行される関数を登録します。これで__destruct()をPHP4でも定義できるようにします。また、__constructというメソッドを、call_user_func_array()で呼び出します。派生したクラスで__constructが定義されると、PHP4でもそれが呼ばれるようになります。派生クラスの__construct内では、parent::__construct();を呼ぶようにします。$this->User->findByTitle('CakePHPとajax'); $this->User->findByName('phpnut'); $this->User->findByAddress('東京都');
overload()関数がきちんと使えるのはそれ以降のバージョンです。CakePHPの環境要件がPHP4.3.2以上となっているのはこれが理由です。「model_php4.php」と「model_php5.phpの」__call()と、「libs/model/datasources/dbo_source.php」のquery()関数を読んでみると、どのようにしてこの処理が実現されているかを見ることができます。関心のある方は研究してください。まとめ
フレームワークの利用は、人を雇って作業をしてもらうのに似ています。開発者が書く必要のあるコードが減り、セキュリティや各DBの違いなどこまごまとしした部分の作業はフレームワークが面倒をみてくれますので開発効率は驚くほど向上します。その一方で、自分には覚えのないバグが入る可能性も否めません(多くの人が使っているフレームワークであれば、大半の部分が徹底的にテストされ、改善されていきますが……)。そんな時、フレームワークの動作の仕組みを理解していると、解決までの時間が短縮されるはずです。フレームワークを上手に使って、どんなWEBアプリケーション開発案件にも笑顔で対応できる、そんな開発チームになりたいものですね。


