问题描述
||
我正在使用PHP4Delphi组件与PHP5ts.dll交互,将PHP嵌入我的应用程序(用Delphi 2010编写)中。
我猜我的程序充当了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,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
爱因
解决方法
这是我的工作范围:
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可以为我解决问题,我不知道为什么,只是尝试了很多次,才发现了这一点。
,由于您的问题很长,我将把答案分成几个部分。
PHP4Delphi组件充当SAPI模块。 ISAPI SAPI模块被用作其原型
您正在使用哪个版本的PHP4Delphi?在我的副本中,调用tsrm_shutdown();位于行1509,而不是1497
我建议以以下方式读取数组:
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,0);
_array_init(smonths,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;
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}