JSON関数が有効なPHP環境ではJavascirptヘルパーのobjectメソッドのstringKeys
、quoteKeys
、q
が効かなくなります。
これは良いのか?って思う仕様。
CakePHP 1.2.5で確認。
まずはCakePHPのマニュアルを確認。
もともとあまり語られてません。APIリファレンスを覗いてみます。
第3引数以降は廃止予定ですが(というかすでに使われてないように見える)、代わりに第2引数の$options
にまとめる形になっています。
block
、prefix
、postfix
、stringKeys
、quoteKeys
、q
とあるのですが、なんとJSON関数が有効なPHP環境で動作させた場合は、stringKeys
、quoteKeys
、q
が無視されてしまいます。
下記のソースを参照すれば確認できます。
cake/libs/views/helpers/javascript.php::object()
if ($this->useNative) {
$rt = json_encode($data);
} else {
if (is_null($data)) {
return 'null';
}
if (is_bool($data)) {
return $data ? 'true' : 'false';
}
if (is_array($data)) {
$keys = array_keys($data);
}
if (!empty($keys)) {
$numeric = (array_values($keys) === array_keys(array_values($keys)));
}
foreach ($data as $key => $val) {
if (is_array($val) || is_object($val)) {
$val = $this->object($val, array_merge($options, array('block' => false)));
} else {
$quoteStrings = (
!count($options['stringKeys']) ||
($options['quoteKeys'] && in_array($key, $options['stringKeys'], true)) ||
(!$options['quoteKeys'] && !in_array($key, $options['stringKeys'], true))
);
$val = $this->value($val, $quoteStrings);
}
if (!$numeric) {
$val = $options['q'] . $this->value($key, false) . $options['q'] . ':' . $val;
}
$out[] = $val;
}
if (!$numeric) {
$rt = '{' . join(',', $out) . '}';
} else {
$rt = '[' . join(',', $out) . ']';
}
}
613行目の$this->useNative
プロパティを見て分岐しています。614行目がJSON関数を使用する場合でelse以降がCakePHP独自の処理のようです。
見てわかるようにJSON関数には$data
しか渡していません。つまりoptions
で指定した上記のオプション類は使用されていないということがわかります。
ここで$this->useNative
が何なのか探ってみます。まぁ名前からしてネイティブの機能を使うか否かということでしょうが。
cake/libs/views/helpers/javascript.php
function __construct($options = array()) {
if (!empty($options)) {
foreach ($options as $key => $val) {
if (is_numeric($key)) {
$key = $val;
$val = true;
}
switch ($key) {
case 'cache':
break;
case 'safe':
$this->safe = $val;
break;
}
}
}
$this->useNative = function_exists('json_encode');
return parent::__construct($options);
}
コンストラクタで設定されていますが、json_encode
関数の有無以外に何も制御されていません。
検索してもここしか出てこないのでこのままでは動的には変更不能です。
ということでJSON関数が有効な環境でstringKeys
等を使いたい場合はCakePHPライブラリを書き換えるか、JavascriptHelperを継承したヘルパーを作るしかなさそうです。。。
(12/3追記)うそです。何言ってるんだ俺はw要はobjectメソッドを使う前にuseNative
をfalse
にしてしまえばいいわけです。つまり下記のようなコードを噛ませばOKです。解決!
$javascript->useNative = false;
コメント