QIQの設計と実装

QIQエクステンションがやっていることについて。
PHPというかZend Engineでは、コンパイラとエクゼキュータが関数ポインタになっており、それぞれファイルの内容から実行コードを生成するzend_comiple_file、文字列から実行コードを生成するzend_compile_string、実行コードに対応するハンドラを呼び出すzend_executeが定義されています。また、それらのデフォルト実装としてcompile_file()、compile_string()、execute()があります。
言語としては良いか悪いかは別にして、堅くも柔らかくもない独自のポジションにあるPHPですが、コアのZend Engineはコンパイラやエグゼキュータが差し換えられたり、実行時のフックが追加できたりと、実は拡張性に富んでいるのです。でもマルチスレッドと演算子オーバーローディングだけは勘弁な!
QIQではオリジナルのyaccファイル (zend_language_parser.y) に少しだけ手を加えたものから独自の構文解析器qiqparseを生成し、zend_comiple_fileとzend_comiple_stringを組み込みの構文解析器zendparseの代わりにqiqparseを使う関数qiq_compile_fileとqiq_compile_stringで置き換えています。qiq_compile_fileとqiq_compile_stringの中身は、zendparseがqiqparseになっている点を除いては、オリジナルのcompile_fileおよびcompile_stringと同じです。また、字句解析器はそのままzendlexを使っています。実行に関してzend_executeはそのままにしていますが、無名関数とクロージャをサポートするためのユーザ定義実行コードハンドラを登録しています (下図では省略)。
実行とコンパイル: PHPとPHP+QIQ
実行とコンパイル: PHPとPHP+QIQ posted by (C)rsk

一方、APCやeAccelerator等のキャッシュやXdebugのようなデバッガでは、いったんzend_compile_file (ものによってはzend_compile_stringやzend_executeも) が指す関数を別の関数ポインタに退避させた後、zend_compile_fileを独自の関数で上書きしています。その関数では一般的に〈前処理〉→〈元の関数を実行〉→〈後処理〉という処理をしており、理論上は複数組み合わせることも可能です。相性の問題は多分にあると思われますが。
実行とコンパイル: PHP+APC
実行とコンパイル: PHP+APC posted by (C)rsk

しかし、QIQのコンパイラは元のコンパイラを呼ばないので、APC等より先にロードされなければなりません。もし後からロードされた場合はキャッシュが無効になるばかりでなく、予期しない問題が起こる可能性もあります。
この点にさえ注意すれば、QIQのコンパイラが生成する実行コードはクロージャために未使用のイベントを転用している以外はオリジナルのものと全く同じで、クロージャを生成するイベントもユーザ定義ハンドラで処理するので、キャッシュとの互換性も確保されています。
また、Xdebugでも独自のユーザ定義ハンドラを登録していますが、QIQのものとは被っていません。
実行とコンパイル: PHP+QIQ+APC
実行とコンパイル: PHP+QIQ+APC posted by (C)rsk

というわけで、「必ず他のエクステンションより先にロードする」ことさえ守れば、QIQはキャッシュやデバッガとも連携できます。いわんやパッチ版をや。