[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 メーリングリストの案内