app.yml に sprintf で使うパターン定義を書いて, 環境に応じてパスとかを自由に定義できるようにしようとしたんですがね.
prod: hoge_path: "/data/path/%1$s/%2$s/%3$s"
みたいな感じにして,%1$s とかに格納ファイルのディレクトリが入る,とか. 元々は PHP4 で define() 定数だったものを, symfony に移行して同じように app.yml で書こうとしたのだが……
symfony の定義ファイルには「定数を定義値に埋め込む」という機能があって,"%SF_SYMFONY_LIB_DIR%/hogelib" みたいに % で囲んだ値を置換してくれる.
当然,% で囲まれてる範囲内が定数でなければ何もしない……はずなのだけど, sfToolKit::replaceConstants() を見ると, % で囲まれた部分をわざわざ文字列として評価しなおしてるわけですよ.
これがどういう弊害を呼ぶかというと……
上記の sprintf パターン定義のような場合に, "/data/path/%1$s/%2$s/%3$s" の %1$s/% がまず評価されて, 1$s/ という定数は当然ながら存在しないのでこれを文字列として評価, すると $s という変数っぽい何かが出てくるのだが, sfToolKit::replaceConstants() スコープ内に変数 $s が存在しないんでひそかに内部エラーを起こし, 結果,"/data/path/%1/%2$s/%3$s" という文字列が app.yml の値として登録されてしまう.
とりあえずの対応としては……
- 順序指定子を使わず "/data/path/%s/%s/%s" みたく書く.
- 余分な指定子を挟んで "/data/path/%1$-s/%1$-s/%1$-s" とか書く.
- sfToolKit::replaceConstants() を改造して,"%\\1%" をシングルクォートで囲うように書き直す.
今回はとりあえず,余計な指定子を挟む方式でなんとか…… でもなぁ,これ,定数でなかった値を文字列として再評価することに何か正当性あるんだろーか? 普通にバグっぽい気がするなぁ.拙い英語で投げてみるかのう……