Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

symfonyの外部でsymfony関連クラスをautoloadする

先日の第2回設計勉強会でも出てきましたが、現在、LimeではなくPHPUnit3を使ってテストをしてます。フレームワーク非依存になるように作っているためです。
とはいえ、データベースアクセスはPropel/Creoleに依存せざる得ない状況(この辺は割り切りw)なので、テスト時にPropel/Creole関連のクラスは必要になります。しかし、symfonyはrequire_once/include_onceではなくautoloadするようになっているので、テスト時に「クラスがない」と怒られまくります。
そこで、次のようにしてautoload機能をでっち上げ、このファイルをそれぞれの*Test.phpでrequire_onceしてテストを実行してます。今のところ、うまく動いてくれてます。

<?php 
$files = array();
function getList($path) {
    $iter = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($path),
                RecursiveIteratorIterator::SELF_FIRST);
    foreach ($iter as $elem) {
        if ($elem->isFile() && ereg('^.*\.php$', $elem->getFilename())) {
            $files[ereg_replace('(\.class)?\.php', '', $elem->getFilename())] = $elem->getPathname();
        }
    }
    return $files;
}

$files = array_merge($files, getList('/usr/local/lib/php/symfony'));
$files = array_merge($files, getList('/path/to/webapp/lib'));
$files = array_merge($files, getList('/path/to/webapp/apps/frontend/lib'));

file_put_contents('/tmp/.class_list', serialize($files));

function __autoload($class_name) {
    $files = unserialize(file_get_contents('/tmp/.class_list'));
    if ($class_name === '') {
        return;
    }
    if (isset($files[$class_name])) {
        include_once $files[$class_name];
    } else {
        foreach ($files as $key => $value) {
            if (ereg($class_name . '$', $value)) {
                include_once $value;
                return;
            }
        }
    }
    if (preg_match('/^(.*)Peer$/', $class_name, $matches)) {
        BasePeer::getMapBuilder('lib.model.map.' . $matches[1] . 'MapBuilder');
    }
}

ini_set('include_path', ini_get('include_path') . ':/usr/local/lib/php/symfony/vendor/');

Propel::setConfiguration(
    array (
        'propel' =>
        array (
          'datasources' =>
          array (
            'propel' =>
            array (
              'adapter' => 'pgsql',
              'connection' =>
              array (
                'phptype' => 'pgsql',
                'hostspec' => 'localhost',
                'database' => 'database_server',
                'username' => 'dbuser',
                'password' => 'dbpassword',
                'port' => 5432,
                'encoding' => 'utf8',
                'persistent' => true,
                'protocol' => NULL,
                'socket' => NULL,
                'compat_assoc_lower' => NULL,
                'compat_rtrim_string' => NULL,
              ),
            ),
            'default' => 'propel',
          ),
        ),
      ));
Propel::initialize();

クラスが必要になった際に__autoload関数が呼び出されるので、当該クラスファイルをinclude_onceすれば問題ないはず。なので、

キー:クラス名
値 :ファイル名

となるような配列を作り、それを__autoload関数で使う、という寸法です。
また、Propelで作ったmodelクラスは、getMapBuilderメソッドを呼び出しています。こうしないと、単独で使えませんでした。元ネタは。。。あれ?どこかにあったはず。。。

バッドノウハウの固まりみたいなものですが、晒しておきます。