[PHP-users 19364]mb_convert_variablesに配列を指定した時の挙動に関して
Seiji Masugata
s.masugata @ digicom.dnp.co.jp
2003年 12月 16日 (火) 17:36:41 JST
こんにちわ、桝形です。
---------------------------------------------------------------------
OS :Linux2.2.14-5.0/Sun OS5.6(sparc)
Apache :1.3.29
PHP(DSP):4.3.3/4.3.4
---------------------------------------------------------------------
php.ini :
mbstring.language = Japanese
mbstring.internal_encoding = EUC-JP
mbstring.http_input = pass
mbstring.http_output = pass
mbstring.encoding_translation = On
SJIS-win,SJIS,eucJP-win,EUC_JP,UTF-8,UTF-7,ISO-2022-JP,JIS,ASCII
mbstring.substitute_character = none;
mbstring.func_overload = 1
mbstring.script_encoding = SJIS
---------------------------------------------------------------------
この環境で、mb_convert_variablesに配列を指定すると自分が期待した動作
になりません。
自分が期待した動作というのは、指定した配列以外は変換をしないで欲しい
という事です。
しかし、現状では、指定していない配列も変換を行っています。
通常の変数では問題ないのに、配列だと何で駄目なんだろう?
mb.php:
---------------------------------------------------------------------
<?
// mbstring.script_encoding = SJISなので、プログラム
// ファイルはSJISで記述。
?>
<pre>
<?
// 問題ナシ
$Str1 = "桝形";
$Str2 = $Str1;
mb_convert_variables( "SJIS",
mb_detect_order( ),
$Str2 );
var_dump( $Str1 );
var_dump( $Str2 );
// 挙動不信?
$Array1 = array( "桝形" );
$Array2 = $Array1;
mb_convert_variables( "SJIS",
mb_detect_order( ),
$Array2 );
var_dump( $Array1 );
var_dump( $Array2 );
?>
</pre>
---------------------------------------------------------------------
結果:(どれも一緒)
---------------------------------------------------------------------
string(4) "桝形"
string(3) "蔓堕
array(1) {
[0]=>
string(3) "蔓堕
}
array(1) {
[0]=>
string(3) "蔓堕
}
---------------------------------------------------------------------
PHPのマニュアルには、
http://jp.php.net/mb_convert_variables
---------------------------------------------------------------------
vars(3番目以降の引数)は、変換する変数への リファレンスです。
文字列、配列、オブジェクトを指定することが可能 です。
mb_convert_variables() は全てのパラメー タが同じエンコーディング
を有することを仮定します。
---------------------------------------------------------------------
と、あるので、恐らく、内部的にリファレンスがどう扱われているか。。。
なんでしょうけど、
PHP_FUNCTION(mb_convert_variables)
を斜め読みした程度では理解不能。。。って、この動作は仕様ですか?
目的の配列内データに対してグルグルと処理している感じなのでmbstring
ではなく、Zend Engineのhashテーブルの持ち方の問題のような気がして
きました。。。って憶測です。
斜め読みした残骸(インデント関係は自分の都合の良いように編集):
---------------------------------------------------------------------
if (convd != NULL)
{
stack_max = PHP_MBSTR_STACK_BLOCK_SIZE;
stack = (pval ***)safe_emalloc(stack_max, sizeof(pval **), 0);
if (stack != NULL)
{
stack_level = 0;
n = 2;
while (n < argc || stack_level > 0)
{
if (stack_level <= 0)
{
var = args[n++];
if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT)
{
target_hash = HASH_OF(*var);
if (target_hash != NULL)
{ zend_hash_internal_pointer_reset(target_hash); }
}
}
else
{
stack_level--;
var = stack[stack_level];
}
if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT)
{
target_hash = HASH_OF(*var);
if (target_hash != NULL)
{
// ココカラ ↓↓↓↓↓
while (zend_hash_get_current_data(target_hash,
(void **) &hash_entry) != FAILURE)
{
zend_hash_move_forward(target_hash);
if (Z_TYPE_PP(hash_entry) == IS_ARRAY ||
Z_TYPE_PP(hash_entry) == IS_OBJECT)
{
if (stack_level >= stack_max)
{
stack_max += PHP_MBSTR_STACK_BLOCK_SIZE;
ptmp = erealloc(stack, sizeof(pval **)*stack_max);
if (ptmp == NULL)
{
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"stack err at %s:(%d)", __FILE__, __LINE__);
continue;
}
stack = (pval ***)ptmp;
}
stack[stack_level] = var;
stack_level++;
var = hash_entry;
target_hash = HASH_OF(*var);
if (target_hash != NULL)
{
zend_hash_internal_pointer_reset(target_hash);
continue;
}
}
else
if (Z_TYPE_PP(hash_entry) == IS_STRING)
{
string.val = (unsigned char *)Z_STRVAL_PP(hash_entry);
string.len = Z_STRLEN_PP(hash_entry);
ret = mbfl_buffer_converter_feed_result(convd, &string,
&result TSRMLS_CC);
if (ret != NULL)
{
STR_FREE(Z_STRVAL_PP(hash_entry));
Z_STRVAL_PP(hash_entry) = (char *)ret->val;
Z_STRLEN_PP(hash_entry) = ret->len;
}
}
}
// ココマデ ↑↑↑↑↑
}
}
else
if (Z_TYPE_PP(var) == IS_STRING)
{
string.val = (unsigned char *)Z_STRVAL_PP(var);
string.len = Z_STRLEN_PP(var);
ret = mbfl_buffer_converter_feed_result(convd, &string,
&result TSRMLS_CC);
if (ret != NULL)
{
STR_FREE(Z_STRVAL_PP(var));
Z_STRVAL_PP(var) = (char *)ret->val;
Z_STRLEN_PP(var) = ret->len;
}
}
}
efree(stack);
}
mbfl_buffer_converter_delete(convd TSRMLS_CC);
}
---------------------------------------------------------------------
--
Seiji Masugata<s.masugata @ digicom.dnp.co.jp>
PHP-users メーリングリストの案内