Smarty側に特に手を入れずにQuercus上で動かしたった
前回話しに上げた変更の
- property_existsの内部でissetFieldを使わせない
- getFieldでnullの時に次の候補(staticとか__get)とかに行かせずにnullを返す
と言うものでまず最初の爆死がなくなり、次はnullオブジェクトに対してisTrustedTagを呼ぼうとして死、と言う部分だったがこの部分はissetを追っていった所null判定が単純に間違っていた事が分かった。
issetの中でもプロパティに対して行うものはissetFieldを呼ぶが、ここで比較しているnullが単純なNullValue.NULLとの!=になっていた。
isTrustedTagの件は実際に比較先はVarで、実際の値がNullValueであるため、比較した結果非nullと言う扱いになって関数を呼びだそうとし、死と言う流れになっていた。
Value型はeqと言う関数で比較するようになっているように見えるのと、PHPのissetに関しては値がnullの場合はfalseなはずなので、eqを使うほうが正しい。
この部分を試しに書き換えた所、Smarty側には何も手を入れず、簡単なテンプレートをエラー無く表示することができた。
Quercusって修正を送りたい場合どーすると良いんだろう。
今回Quercusの中身を見をみた感想としてはかなり統一感があって見やすい&探しやすいコードになっているように思えた。
githubでPull Request募集したら結構協力者いると思うんだけどなあ。
仕様だってPHPの完全互換を目指す部分は揉めないだろうし。
Quercus上でのproperty_existsと__get
ソースを追ってみたところ、property_existsの方はClassesModuleと言うクラスにあり、内部的にはissetFieldと言う関数を参照していた。
名前から察する通りisset系なのでnullの場合はfalseになるようになっていた。
修正するとしたらissetFieldではなくhasFieldとか別の関数を用意して、それを呼ぶようにしたほうが良いか。
また、プロパティがnullの場合に__getに来てしまう問題だが、これはObjectExtValueと言うクラスにあるgetField系の中身をどうにかしてやる必要がありそうだった。
unsetもしくはnullの場合次の候補へ(__getなどへ)回す処理になっていたため、今回のような非互換な挙動になっていた。
どちらも実験的に上記のような対応を入れてみたところ、残るはisTrustedTagと言う関数をnullオブジェクトに対して呼び出していると言うエラーが出るところまで来た。
こちらの問題はSmartyのコードを見てみると、issetでオブジェクトがfalseかまたはオブジェクトに対してisTrustedTagを呼ぶと言うもので特に問題なく、echoなどで中身を見てみるとissetの結果が正しくない事が分かった。
が、流石にissetが常に正しく動いてなければ互換性もクソも無いだろうと思って実験コードを書いたらやはり挙動は正しく、何か複雑な組み合わせの際に間違った値になってしまっているように見えた。
ちなみに、ここはQuercus側を回収せずissetを!= nullに変えることでその後のエラーを見てみたが、そこを回避できれば簡易的なテンプレートは正しく表示されるところまではいけた。
調べ始めて1〜2日で判明してしまうレベルの問題が3件もあったように見えるが、実際の所これは何で解決されて無いんだろう。
更新頻度は低いが放置してるとまでは行っていないように思えるんだけどな。
あとは最終的に正しい修正箇所がわかった場合にどういった形で修正依頼を出せばいいのか、と言うところだな。githubを使った形跡はあるんだけど、現在はsvnしかなさそうだし、、、
SmartyがQuercusで動かない
しょっぱなから躓いた。ここにある理由の通り。
https://gist.github.com/4086394
property_existsはnullでもプロパティーが存在していればtrueなのにQuercusはそうなっていない。
Smartは__getや__callを結構駆使してるのでしょっぱなでコケる。
しょうがないのでソースを追いかけるか。