昨今の PHP 界隈において、外部依存のパッケージもアプリ内のあらゆるクラスも、その読み込みの際はいちいち require_once
などとは書かずに composer の生成してくれるオートローダーに任せるのが当たり前です。
一方、WordPress においてプラグインやテーマからそれを使うのは(もっといえば広く使われているようなパッケージを使うこと自体も、なのですが)懸念点が大きいため「どんどん使え」というわけには行かない現状があります。
(ちなみに、WordPressにはコアにオートローダーを導入しようみたいなプロポーザルもあるのですが、また別の話。これもしばらく進展がない……)
オートローダーの懸念点
懸念点というのは、複数のプラグインが同一のパッケージを利用していた場合に(当然ながら名前空間が被るため)使用されるバージョンが保証されないといったものです。
たとえばAとBの2つのプラグインがそれぞれcomposerでXというパッケージを利用してい、Aのアップデートがないまま放置していたと仮定します。Xのパッケージは新機能が実装されたり脆弱性修正があるでしょう。Bのパッケージはその新機能を使ったコードをリリースしたとします。
いずれもオートローダーでそのパッケージを登録しているわけですが、運悪くAのオートローダーが利用されてしまうかもしれません。すると、当然ながら呼び出されたパッケージXは新機能を持っていないのでエラーが発生してしまいます。
新しいオートローダー
そこで、Automattic は Jetpack に新しいオートローダーを導入しました。
Add Custom Autoloader by enejb · Pull Request #12447 · Automattic/jetpack
このオートローダーは先日beta1が公開されたばかりのJetpack 7.5から実際に使用されています。
このオートローダーについて
Jetpackの新しいオートローダー、 automattic/jetpack-autoloader
は、名前にこそJetpackと入っていますが当然他のプラグインでも使用できます。むしろ様々なプラグインで共通して利用されてこそ真価を発揮するものになっています。
というのも、このオートローダーは生成するクラスマップに各パッケージのバージョン情報を持ちjetpack-autoloaderを利用するプラグインのオートローダー間で共有、よりバージョンの高いものをオートロードで読み込むように設計・実装されています。
このため、プラグイン間の依存パッケージのバージョン差異に悩む必要性が低くなるでしょう。当然ながら破壊的な大きなアップデートが入ると影響をうけてしまうでしょうが…(なおクラスマップは完全修飾名で衝突判定をかけるためバージョン間で名前空間ごと変更になった場合はどちらも併用できることになります。一部だけ衝突しているとかが無ければ…)
なお、Readme 曰く現状PSR-4で名前空間の切られたパッケージのみ利用可能なようです。(といいつつ classmap
のサポートも追加されたところっぽい)
PHP汎用パッケージだと使いにくくてもWPプラグイン向けに用意したパッケージでは則っておけば大丈夫、みたいなのはあり得るかも。
なお、オートロードを正しく機能させるためオートロードによるクラスの呼び出しはすべてのプラグインが読み込まれた plugins_loaded
アクション以降でのみ利用可、という制約があります。(待たずにオートロードが走るとせっかくのオートローダーが無駄になってしまいますからね)
オートローダーを試してみる
では実際に試してみます。ホントは複数プラグインでバージョン競合をさせて正しく機能してるのか試すべきところなんですがそんな暇もないので新規プラグインで導入してみるサンプルまで。
1 2 3 4 5 |
cd path/to/wp-content/plugins wp scaffold plugin my-autoload-sample cd my-autoload-sample composer init composer require --dev automattic/jetpack-autoloader:^1 |
あとはプラグインの先頭にオートローダー読み込みの1行を付け足すのみ。
1 |
require_once . plugin_dir_path( __FILE__ ) . '/vendor/autoload_packages.php'; |
あとは任意のパッケージをcomposerで追加しつつ普段どおりコードを書くのみ。
ところでJetpackではモノレポ的に内部パッケージを扱っているので、そのコードを取り入れて動作を試してみた。
https://github.com/hinaloe/try-jetpack-autoloader
オートローダーは期待通りうまく動いていることが確認できたのだが、一方でモノリポとして@dev
で指定されているパッケージはバージョンが9999999-devとして扱われている。composerのバージョン指定の仕様上仕方ない気はするが、このあたりなにかもう少しましな運用ができないものなのだろうか……(なおオートローダー自体はsubtreeかなんかでpackagist用のミラーリポを用意している模様……)
〆
なにはともあれこの新しいオートローダー、先述の通り幅広く使われてこそ真価が発揮できます。まだまだ機能不足だったり不安定だったりするかもしれませんが、WPプラグイン開発の際は思い出してみてください。