悪用厳禁! ZF2のPluginClassLoader::addStaticMap
こんな場末の日記をご覧の方は、ZF2のプラグイン機構では、クラス定義の読み込みをPluginClassLoaderが、インスタンス化をPluginBrokerが行うということはご存知ですよね!え、ご存知ない?Wikipedia創設者ZFリードデペロッパーMatthew Weier O'Phinneyからのメッセージをお読みください。
Introducing the ZF2 Plugin Broker
http://weierophinney.net/matthew/archives/248-Introducing-the-ZF2-Plugin-Broker.html
で、LazyLoadingをする場合は、PlginBrokerの拡張PluginSpecBrokerというのが存在します。
(Controller\Actionでは、Loader\PluginSpecBrokerの拡張のController\Action\HelperBrokerを
ヘルパー読み込みの際に使用。View\PhpRendererでは、Loader\PluginBrokerの拡張のView\HelperBrokerを使用)
ということで、プラグイン機構を自前のライブラリで使う場合に以下のように使う場合に以下のような構造を考えるわけですが、
<?php namespace Diggin\Service\ShortUrl; class ShortUrl { protected $shortUrlBroker; // host名=$plugin名としてpreg_replace_callbackに渡すなどする包括的なフィルタ用 public function unshorten($plugin, $shortenedUrl) { if ($shortener = $this->getShortUrlBroker()->load($plugin)) { if ($shortener instanceof \Zend_Service_ShortUrl_Shortener) { return $shortener->unshorten($shortenUrl); } else if ($shortener instanceof \Services_ShortUrl) { } return $shortenedUrl; } return $shortenedUrl; } public function getShortUrlBroker() { if (!$this->shortUrlBroker instanceof ShortUrlBroker) { $this->shortUrlBroker = new ShortUrlBroker; } return $this->shortUrlBroker; } }
<?php namespace Diggin\Service\ShortUrl; use Zend\Loader\PluginSpecBroker; class ShortUrlBroker extends PluginSpecBroker { protected $defaultClassLoader = 'Diggin\Service\ShortUrl\ShortUrlClassLoader'; }
<?php namespace Diggin\Service\ShortUrl; use Zend\Loader\PluginClassLoader; class ShortUrlClassLoader extends PluginClassLoader { protected $plugins = array( 'tinyurl' => 'Zend_Service_ShortUrl_TinyUrlCom', 'isgd' => 'Zend_Service_ShortUrl_IsGd', 'metamark' => 'Zend_Service_ShortUrl_MetamarkNet', ); }
ここで、メンドくさがって、BrokerにvalidatePlugin()の個別処理を書かないと、以下のような呼び出しをしたときに
<?php set_include_path(__DIR__.'/library/'. PATH_SEPARATOR .get_include_path()); require_once 'Zend/Loader/StandardAutoloader.php'; $loader = new Zend\Loader\StandardAutoloader; //$loader->registerNamespace('Diggin'); $loader->setFallbackAutoloader(true); $loader->register(); //bootstrapなどで Zend\Loader\PluginClassLoader::addStaticMap(array('tinyurl' => 'Zend\Version')); //bootstrapなででtypoした場合 Diggin\Service\ShortUrl\ShortUrlClassLoader::addStaticMap(array('tonyurl' => 'User\ShortUrl\Type')); use Diggin\Service\ShortUrl\ShortUrl; $shorturl = new ShortUrl; var_dump($shorturl->getShortUrlBroker()->load('tinyurl')); //Zend\Version
という感じで処理がインスタンス生成後もヘルパーコールの場合処理がそのまま起動されちゃいます。なので、読み込み後インスタンスが適切か確認するvalidatePluginはちゃんと書かないとだめですね。
<?php namespace Diggin\Service\ShortUrl; use Zend\Loader\PluginSpecBroker; class ShortUrlBroker extends PluginSpecBroker { protected $defaultClassLoader = 'Diggin\Service\ShortUrl\ShortUrlClassLoader'; protected function validatePlugin($plugin) { if (!$plugin instanceof \Zend_Service_ShortUrl_Shortener) { throw new Exception\RuntimeException('Serializer adapters must implement Zend\Serializer\Adapter'); } return true; } }
まあ、この自前コンポネーント設計どうなのよって話もありますが。