読者です 読者をやめる 読者になる 読者になる

俺の彼女と幼なじみとPHPとAutoloadが修羅場すぎる(classmapのはなし)

PHPのことを一晩中考えてる皆さん!Autoload使ってますか!

- 「PHP5.3世代の最新フレームワーク使ってるから当然使ってるよ!」(キリッ!)
- 「is_aの挙動の変更はまさにPHPっぽいと断言できる!」(キリッ!)
- 「vendor/.composer/autoload.phpをリクワイアするのハもうオーベイではジョーシキデース!」(キリッ!)

なるほど!!


残念!そちらのPHPのオートローディング機能そのものではなく、
http://jp.php.net/autoload

theseer/Autoload のほうです。
https://github.com/theseer/Autoload

PHPカンファレンスのスライドにも載っけてます。
http://www.slideshare.net/sasezaki/php-9151036/51


PHPカンファレンスでも話した通り、psr-0に沿えば良いし、SplClassLoaderとか使って、spl_autoload_registerにクラスローダと名前空間を登録すれば良いと思います。最近のライブラリ使って開発してる限りでは。。で、上記スライドに挙げてる通りパフォーマンス上の問題もありますけれども、psr-0に沿わないクラスファイルローディングにも効力を発揮するのが、theseer/Autoloadです。

githubでの説明では"A lightweight php namespace aware autoload generator"となってますが、要するにclassmap generatorです。

classmap?

クラス名とファイル一覧のセットを指します。
http://www.slideshare.net/sasezaki/php-9151036/50

念のために言うと、autoloadが実行されたときにこのclassmapに基づきファイルがロード(遅延ロード)されるため、
すべてのファイルをindex.phpとかブートストラップなところでrequire_onceを全て書いてるのとかは意味が違います。

使い方

  • ヘルプ

$ phpab -h

でヘルプがでてきます。

(Miffieの例)

$ phpab -n -b src/Miffie -o src/Miffie/Autoload.php -i "src/Miffie*" src

pyrus genereate-pear2で作った雛形(ようするにsrcがコンポーネントdirの場合)だとこんな感じ、で下のようなものができます。

<?php
// @codingStandardsIgnoreFile
// @codeCoverageIgnoreStart
// this is an autogenerated file - do not edit
spl_autoload_register(
    function($class) {
        static $classes = null;
        if ($classes === null) {
            $classes = array(
                'Miffie\\CLIRunner' => '/CLIRunner.php',
                'Miffie\\GetoptExt' => '/GetoptExt.php',
                'Miffie\\Spider' => '/Spider.php'
            );
        }
        if (isset($classes[$class])) {
            require __DIR__ . $classes[$class];
        }
     }
);
// @codeCoverageIgnoreEnd
  • 配列の返却のみにしたい場合

-t(--template)の引数に作成したテンプレートを用意します。

↑のファイルを-tオプションの引数に指定すると、↓といったアウトプットになります

<?php
return array(
'Miffie\\CLIRunner' => '/CLIRunner.php',
                'Miffie\\GetoptExt' => '/GetoptExt.php',
                'Miffie\\Spider' => '/Spider.php'
);
  • アレなソースの判定にも使える

昔のソースだとif分岐でclass定義を2回書いてたりしますので、wordpressフォルダ配下で

$ phpab wp-includes

なーんてやると、

phpab 1.6.0 - Copyright (C) 2009 - 2011 by Arne Blankerts

Error while processing request:
 - Redeclaration of class 'services_json_error' detected
   Original:  wp-includes/class-json.php
   Secondary: wp-includes/class-json.php

エラーになるので、エラーとなったコードファイルの個別対応が必要になりますがtolerantオプションで無視するか--excludeオプションで、

$ phpab -n -e "*class-json.php" wp-includes

とやると一応class-json.phpを無視した形でのクラスマップは作成できます。

名称(phpab)について

さて、このAutoload(phpab)名前が紛らわしい。googleビリティへの配慮が欠けてる。と思われるかも知れませんが、thePHP.ccの面々は前々からこんな感じのプロダクト名ばっかりなので気にしたら負けです。ちなみにphpabはAutoloadなんとかの略ではなく、作者が Arne Blankerts のためその略だと思われます。んがんぐ。

あれZend Framework2にも似たものが?

はい、ありますね。。
http://framework.zend.com/wiki/display/ZFDEV2/Proposal+For+Autoloading+In+ZF2
微妙に違って、https://gist.github.com/1601031のように手を加えないとだめそうです。