sirven que para los ejemplos bidimensionales arreglos delphi delphi-2010 php-extension php-internals php4delphi

delphi - que - arreglos bidimensionales java



Intercambio de datos con zend(matrices multidimensionales) (2)

Estoy incorporando PHP en mi aplicación (escrito en Delphi 2010), usando el componente PHP4Delphi para interactuar con php5ts.dll. Supongo que mi programa actúa como una extensión para el PHP (¿Módulo sapi?) Ya que registra algunas funciones y constantes que se pueden usar en scripts PHP ... de todos modos, funciona bien cuando se usan tipos de datos simples, pero cuando trato de usar una matriz multidimensional como valor de retorno me sale un error

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

La línea 1497 en php4delphi.pas es llamada a tsrm_shutdown();

Para mí, parece que el recolector de basura se cuelga al final del script, así que sospecho que no envío los datos correctamente al motor ... así que mi pregunta es ¿cómo se supone que se deben enviar matrices multidimensionales a PHP?
El patrón que estoy usando es

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;

¿Tengo que "registrar" en algún lugar los subarrays que creo? ¿Debo aumentar o disminuir el refcount o establecer is_ref ? IOW, ¿cómo deben establecerse return_value y zvals de los subarreglos?
Experimenté añadiendo 1 al recuento de cada matriz (aunque MAKE_STD_ZVAL ya inicializa el refcount a 1) y eso cura el AV, pero a veces la aplicación simplemente desaparece al ejecutar el script. Sospecho que causa una recursión infinita en el administrador de memoria del motor, bloqueando el DLL de php y llevándose la aplicación ... Cuando se establece el recuento de refinanciación en 0 (cero; suponiendo que cuando se asigna valor de retorno en el guión PHP, el recuento será 1 y luego, cuando la variable PHP salga del alcance, se destruirá), todo parece trabajo (es decir, sin bloqueo, sin AV) pero el script no generará ningún resultado, solo archivo html vacío ...

También envío datos como matrices en mi función, luego uso zend_hash_find , zend_hash_get_current_data , etc. para leer los datos. ¿Podría esto arruinar los recuentos de las variables? ¿Debo disminuir la refcout de la variable devuelta por zend_hash_find cuando haya terminado?
Y ¿es seguro reutilizar la misma variable cuando se itera sobre una matriz, es decir,

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);

o debería cada iteración del ciclo crear / liberar Val?

TIA
ain


Como su pregunta es bastante larga, dividiré mi respuesta en pocas partes.

  1. El componente PHP4Delphi actúa como módulo SAPI. El módulo ISAPI SAPI fue utilizado como un prototipo para él
  2. ¿Qué versión de PHP4Delphi estás usando? En mi copia, la llamada a tsrm_shutdown (); está ubicado en la línea 1509, no en 1497
  3. Propondría leer la matriz de la siguiente manera:

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. Algunas personas informaron sobre los problemas con los índices enteros para las matrices. Yo propondría cambiar el índice a cadena:

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. El error en tsrm_shutdown generalmente está relacionado con la gestión de la memoria y las cadenas Delphi. php5ts.dll tiene un administrador de memoria incorporado y funciona de forma independiente desde el administrador de memoria Delphi. Cuando la referencia de la cadena es igual a cero desde el punto de vista de Delphi, puede desasignarse, pero al mismo tiempo puede seguir siendo utilizada por el motor de PHP. Si llena los subarreglos con cadenas, asegúrese de que el administrador de memoria Delphi no recoja las cadenas. Por ejemplo, puede convertir las cadenas en PAnsiChar antes de agregarlo a la matriz

{$IFNDEF COMPILER_VC9} fnc^.internal_function.function_name := strdup(method_name); {$ELSE} fnc^.internal_function.function_name := DupStr(method_name); {$ENDIF}


aquí está mi trabajo alrededor:

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

Establezca el recuento de ref 2 para resolver el problema, no sé por qué, lo intenté muchas veces y encontré esto.