Я пишу некоторый код-оболочку, используя SWIG, чтобы выставить мои функции C++ для PHP.
мой_модуль.i
%module phpMyModule
%include "exception.i"
%include "std_string.i"
%include "typemaps.i"
// INPUT: convert PHP native array to std::vector<std::string>
%typemap(in) const std::vector<std::string> & %{
if (Z_TYPE($input) == IS_ARRAY) {
std::vector<std::string> temp2;
$1 = &temp2;
HashTable *ht = Z_ARRVAL($input);
zval *data;
HashPosition pos;
for (zend_hash_internal_pointer_reset_ex(ht, &pos);
(data = zend_hash_get_current_data_ex(ht, &pos)) != nullptr;
zend_hash_move_forward_ex(ht, &pos)
) {
convert_to_string(data);
$1->push_back( std::string( Z_STRVAL_P(data), Z_STRLEN_P(data) ) );
}
}
else SWIG_exception( SWIG_TypeError, "Type Error: Only PHP array is supported!" );
%}
%{
#include "MyModule.h"
%}
extern int initialize_engine( const std::string& script_file, const std::vector<std::string>& input_vars );
Созданный SWIG код оболочки
ZEND_NAMED_FUNCTION(_wrap_initialize_engine) {
std::string *arg1 = 0 ;
std::vector< std::string > *arg2 = 0 ;
std::string temp1 ;
zval args[2];
int result;
SWIG_ResetError();
if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {
WRONG_PARAM_COUNT;
}
convert_to_string(&args[0]);
temp1.assign(Z_STRVAL(args[0]), Z_STRLEN(args[0]));
arg1 = &temp1;
if (Z_TYPE(args[1]) == IS_ARRAY) {
std::vector<std::string> temp2;
arg2 = &temp2;
HashTable *ht = Z_ARRVAL(args[1]);
zval *data;
HashPosition pos;
for (zend_hash_internal_pointer_reset_ex(ht, &pos);
(data = zend_hash_get_current_data_ex(ht, &pos)) != nullptr;
zend_hash_move_forward_ex(ht, &pos)
) {
convert_to_string(data);
arg2->push_back( std::string( Z_STRVAL_P(data), Z_STRLEN_P(data) ) );
}
}
else SWIG_exception( SWIG_TypeError, "Type Error: Only PHP array is supported!" );
result = (int)initialize_engine((std::string const &)*arg1,(std::vector< std::string > const &)*arg2);
RETVAL_LONG(result);
thrown:
return;
fail:
SWIG_FAIL();
}
test.php
<?php
require_once '<path>/<to>/phpMyModule.php';
$handle = phpMyModule::initialize_engine(
'<path>/<to>/test.script',
["var1", "var2", "var3"]
);
echo "Handle #1 Value: $handle\n";
phpMyModule::terminate_engine($handle);
?>
По сути, приведенный выше код вызывает _wrap_initialize_engine()
со строкой PHP (script_file
) и массивом имен переменных PHP (input_vars
). SWIG использует typemap
для преобразования строки и массива PHP в std::string и std::vector соответственно, а затем вызывает настоящий initialize_engine()
.
В initialize_engine( const std::string& script_file, const std::vector<std::string>& input_vars )
у меня есть:
std::for_each( input_vars.begin(), input_vars.end(), [&]( const std::string& name ) {
std::cout << "Adding " << name << " ..." << std::endl;
// signature is Data::addVariable( const std::string& name, const VariableVector& values );
// Data::VariableVector is actually std::vector<double>
data.addVariable( name, Data::VariableVector() );
} );
Это работает. Распечатка
Adding var1 ...
Adding var2 ...
...
Но если я закомментирую std::cout ...
, все вызовы data.addVariable()
получат пустую строку для аргумента name
. (Я знаю это, потому что внутри вызова я проверяю имя на соответствие существующим именам и выдаю ошибку, когда используются дубликаты. Без std::cout ...
я получил сообщение об ошибке, говорящее, что «имя» уже существует»...)
Мой вопрос
Как это могло случиться? На const std::vector<std::string>&
не должно влиять то, вызываю ли я на нем std::cout
.
Мое единственное предположение было бы в том, что std::string повторно использовал точки char* вместо их копирования? Если это так, то настоящие буферы все еще находятся внутри PHP и могли быть изменены? Я считаю, что это не должно иметь место, но просто хочу, чтобы кто-то с лучшим знанием C++ подтвердил это для меня.
Но если это было не так, то почему происходит вышеописанное странное поведение?
temp2
непосредственно перед вызовомmy_cpp_function
. - person R Sahu   schedule 27.11.2017my_cpp_function()
, и вывод правильный. Однако использование или неиспользование std::cout внутри my_cpp_function по-прежнему приводит к разным результатам. - person yhf8377   schedule 27.11.2017data.addVariable
()? - person Phil Brubaker   schedule 27.11.2017