我在我的应用程序中嵌入了PHP(在Delphi 2010中编写),使用PHP4Delphi组件与php5ts.dll进行交互。 我想我的程序充当PHP(sapi模块?)的扩展,因为它注册了一些可以在PHP脚本中使用的函数和常量......无论如何,在使用简单数据类型时效果很好,但是当我尝试使用多维数组时作为返回值我得到错误
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_data
等来读取数据。这会搞砸变量的重新计算吗?即,当我完成它时,我是否必须减少zend_hash_find
返回的变量的refcout?
迭代数组时重用同一变量是安全的,即
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?
TIA
AIN
答案 0 :(得分: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为我解决问题,我不知道为什么,只是多次尝试,并找到了这个。
答案 1 :(得分:1)
由于你的问题很长,我会在几个部分中分开我的答案。
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;
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;
{$IFNDEF COMPILER_VC9}
fnc^.internal_function.function_name := strdup(method_name);
{$ELSE}
fnc^.internal_function.function_name := DupStr(method_name);
{$ENDIF}