【问题标题】:SWIG and PHP7: Strange string vector behaviourSWIG 和 PHP7:奇怪的字符串向量行为
【发布时间】:2017-11-27 18:11:49
【问题描述】:

我正在使用 SWIG 编写一些包装器代码,以将我的 C++ 函数公开给 PHP。

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

?>

上面的代码基本上是用一个 PHP 字符串 (script_file) 和一个 PHP 变量名数组 (input_vars) 调用 _wrap_initialize_engine()。 SWIG 使用typemap 将PHP 字符串和数组相应地转换为std::string 和std::vector,然后调用真正的initialize_engine()

initialize_engine( const std::string&amp; script_file, const std::vector&lt;std::string&gt;&amp; 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&lt;std::string&gt;&amp; 不应该受到我是否调用 std::cout 的影响。

我唯一的猜测是 std::string 重新使用了 char* 点而不是复制它们?如果是这种情况,那么真正的缓冲区仍在 PHP 中并且可能已更改?我认为情况不应该是这样,只是希望有更好的 C++ 知识的人为我确认。

但如果不是这样,那么为什么会出现上述奇怪的行为呢?

【问题讨论】:

  • std::string 进行复制。
  • 发布的代码看起来没问题。很难说是什么导致了您所看到的问题。您可以做的一件事是在调用 my_cpp_function 之前添加几行代码以打印 temp2 的内容。
  • @RSahu 我在调用my_cpp_function() 之前添加了另一个std::cout 并且输出是正确的。但是在 my_cpp_function 中使用或不使用 std::cout 仍然会产生不同的结果。
  • data.addVariable() 的签名是什么?

标签: c++ swig php-7


【解决方案1】:

原来是我犯了一个愚蠢的错误……对不起……

my_module.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> & %{
    std::vector<std::string> temp2;  // should be declared here!
    if (Z_TYPE($input) == IS_ARRAY) {
        // if declared here, temp2 will be released before init_engine() was called!
        // Wrong: std::vector<std::string> temp2;
        $1 = &temp2;
        ......
}
else SWIG_exception( SWIG_TypeError, "Type Error: Only PHP array is supported!" );

%}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-14
    相关资源
    最近更新 更多