22

PHP4Delphi コンポーネントを使用して php5ts.dll とのインターフェイスを使用して、アプリ (Delphi 2010 で記述) に PHP を埋め込んでいます。PHPスクリプトで使用できるいくつかの関数と定数を登録するため、私のプログラムはPHP(sapiモジュール?)の拡張機能として機能すると思います...とにかく、単純なデータ型を使用する場合はうまく機能しますが、多次元配列を使用しようとすると戻り値としてエラーが発生します

Access violation at address 01CD3C35 in module 'php5ts.dll'. Read of address 0231E608.
スタックリスト
(000A2C35){php5ts.dll} [01CD3C35] destroy_op_array + $35
(004C4D61){myApp.exe } [008C5D61] php4delphi.TPHPEngine.ShutdownEngine (Line 1497, "php4delphi.pas" + 17) + $7

php4delphi.pas の 1497 行が呼び出されます。tsrm_shutdown();

私には、スクリプトの最後でガベージコレクターがクラッシュしているように見えるので、エンジンにデータを正しく送り返していないのではないかと疑っています...したがって、多次元配列をPHPに送り返す方法が私の質問ですか?
私が使っているパターンは

var subArray: pzval;  
_array_init(return_value, nil, 0);  
for x := 0 to Data.Count-1 do begin  
   subArray := MAKE_STD_ZVAL;  
   _array_init(subArray, nil, 0);  
   // populate subarray with data, including other subarrays
   ...
   // add subarray to the main array
   add_index_zval(return_value, x, subArray);
end;

作成したサブアレイをどこかに「登録」する必要がありますか? 増減refcountまたは設定する必要がありis_refますか? IOW、サブ配列の return_value と zvals をどのように設定する必要がありますか?
各配列のrefcountに1を追加して実験しました(MAKE_STD_ZVALはすでにrefcountを1に初期化していますが)、これでAVは解決しますが、スクリプトを実行するとアプリが消えることがあります-エンジンのメモリマネージャーで無限再帰が発生し、php DLLがクラッシュし、アプリを持っていく... refcountを0に設定すると(ゼロ; PHPスクリプトで戻り値が割り当てられたときにrefcountが1になり、PHP変数がスコープ外になると破棄されると仮定すると)すべてのようです動作します(つまり、クラッシュもAVもありません)が、スクリプトは出力を生成せず、空のhtmlファイルのみを生成します...

また、データを配列として関数に送信し、zend_hash_find, zend_hash_get_current_dataetc を使用してデータを読み取ります。これにより、変数の参照カウントが台無しになる可能性はありますか? つまり、使い終わったときに返される変数のrefoutを減らす必要がありますzend_hash_findか?
また、配列を反復処理するときに同じ変数を再利用しても安全ですか。つまり、

var Val: pppzval;
new(Val);
zend_hash_internal_pointer_reset(aZendArr^.value.ht);
for x := 1 to zend_hash_num_elements(aZendArr^.value.ht) do begin
   zend_hash_get_current_data(aZendArr^.value.ht, Val);
   // read data from Val to local variable and do something with it
   zend_hash_move_forward_ex(aZendArr^.value.ht, nil);
end;
Dispose(Val);

または、ループの各反復で Val を作成/解放する必要がありますか?

ティア
・アイン

4

2 に答える 2

2

ここに私の仕事があります:

function InitSubArray(TSRMLS_DC : pointer):pzval;
begin
  Result := MAKE_STD_ZVAL;
  Result^.refcount:=2;
  Result^._type:=IS_ARRAY;
  InitPHPArray(Result,TSRMLS_DC);
end;

refcount を 2 に設定して問題を解決してください。理由はわかりません。何度も試してみたところ、これが見つかりました。

于 2012-01-12T12:06:32.917 に答える
1

あなたの質問はかなり長いので、私は私の答えをいくつかの部分に分けます。

  1. PHP4DelphiコンポーネントはSAPIモジュールとして機能します。ISAPISAPIモジュールがそのプロトタイプとして使用されました
  2. どのバージョンのPHP4Delphiを使用していますか?私のコピーでは、tsrm_shutdown();の呼び出しです。1497ではなく1509行にあります
  3. 次の方法で配列を読み取ることを提案します。
procedure TForm1.ExecuteGetArray(Sender: TObject;
  Parameters: TFunctionParams; var ReturnValue: Variant;
  ZendVar: TZendVariable; TSRMLS_DC: Pointer);
var
  ht  : PHashTable;
  data: ^ppzval;
  cnt : integer;
  variable : pzval;
  tmp : ^ppzval;
begin
  ht := GetSymbolsTable;
  if Assigned(ht) then
   begin
      new(data);
       if zend_hash_find(ht, 'ar', 3, data) = SUCCESS then
          begin
            variable := data^^;
            if variable^._type = IS_ARRAY then
             begin
               SetLength(ar, zend_hash_num_elements(variable^.value.ht));
               for cnt := 0 to zend_hash_num_elements(variable^.value.ht) -1  do
                begin
                  new(tmp);
                  zend_hash_index_find(variable^.value.ht, cnt, tmp);
                  ar[cnt] := tmp^^^.value.str.val;
                  freemem(tmp);
                end;
             end;
          end;
       freemem(data);
   end;
end;
  1. 一部の人々は、配列の整数インデックスの問題について報告しました。インデックスを文字列に変更することを提案します。
procedure TPHPExtension1.PHPExtension1Functions1Execute(Sender: TObject;
  Parameters: TFunctionParams; var ReturnValue: Variant; ZendVar : TZendVariable;
  TSRMLS_DC: Pointer);
var
  pval : pzval;
  cnt  : integer;
  months : pzval;
  smonths : pzval;
begin
 pval := ZendVar.AsZendVariable;
 if _array_init(pval, nil, 0) = FAILURE then
  begin
    php_error_docref(nil , TSRMLS_DC, E_ERROR, 'Unable to initialize array');
    ZVAL_FALSE(pval);
    Exit;
  end;

  months := MAKE_STD_ZVAL;
  smonths := MAKE_STD_ZVAL;

  _array_init(months, nil, 0);
  _array_init(smonths, nil, 0);

  for cnt := 1 to 12 do
   begin
     add_next_index_string(months, PChar(LongMonthNames[cnt]), 1);
     add_next_index_string(smonths, PChar(ShortMonthNames[cnt]), 1);
   end;

  add_assoc_zval_ex(pval, 'months', strlen('months') + 1, months);
  add_assoc_zval_ex(pval, 'abbrevmonths', strlen('abbrevmonths') + 1, smonths);

end;
  1. tsrm_shutdownのエラーは通常、メモリ管理とDelphi文字列に関連しています。php5ts.dllにはメモリマネージャが組み込まれており、Delphiメモリマネージャから独立して動作します。Delphiの観点から文字列参照がゼロに等しい場合、割り当てを解除できますが、同時にPHPエンジンで引き続き使用できます。サブ配列に文字列を入力する場合は、文字列がDelphiメモリマネージャによって収集されないようにしてください。たとえば、文字列を配列に追加する前に、文字列をPAnsiCharに変換できます。
{$IFNDEF COMPILER_VC9}
fnc^.internal_function.function_name := strdup(method_name);
{$ELSE}
fnc^.internal_function.function_name := DupStr(method_name);
{$ENDIF}
于 2011-09-27T21:08:01.263 に答える