Как использовать std::vector в PHP с помощью SWIG
Я работаю над оберткой С++ API в PHP с помощью SWIG. Я больше всего нахожусь там, но у меня возникают проблемы с функцией, которая возвращает вектор. Заголовок выглядит примерно так:
#include <vector>
namespace STF
{
class MyClass
{
public:
const std::vector<MyOtherClass> &getList();
};
}
Файл интерфейса выглядит следующим образом:
%include <std_vector.i>
%import "STF_MyOtherClass.i"
%{
#include "STF_MyOtherClass.h"
#include "STF_MyClass.h"
%}
%include "STF_MyClass.h"
Кажется, я могу назвать функцию прекрасной, но она возвращает ресурс PHP вместо объекта. В частности, это ресурс типа: "_p_std__vectorT_STF__MyClass_t".
Как я могу получить это, чтобы вернуть объект, через который я могу выполнить итерацию (желательно с помощью цикла foreach), или как я могу перебирать этот ресурс?
Update:
Я работал над решением, основанным на том, что я читал здесь: http://permalink.gmane.org/gmane.comp.programming.swig/16817
В основном я пытаюсь преобразовать вектор в массив python:
%typemap(out) std::vector<STF::MyOtherClass>
{
array_init( return_value );
std::vector<STF::MyOtherClass>::iterator itr;
itr = $1.begin();
for( itr; itr != $1.end(); itr++ )
{
zval* tmp;
MAKE_STD_ZVAL( tmp );
SWIG_SetPointerZval( tmp, &*itr, $descriptor(STF::MyOtherClass*), 2 );
add_next_index_zval( return_value, tmp );
}
}
Это очень близко к работе. Я установил точку останова внутри кода оболочки в SWIG_ZTS_SetPointerZval. Когда он переходит к инициализации объекта, он выполняет zend_lookup_class для "stf__myotherclass", который терпит неудачу (он не находит clasS). Я не уверен, почему он не может найти класс.
Ответы
Ответ 1
В конце концов, это то, что я сделал для преобразования вектора в массив PHP (поместите его в файл интерфейса для MyOtherClass):
%typemap(out) const std::vector<STF::MyOtherClass>&
{
array_init( return_value );
std::vector<STF::MyOtherClass>::const_iterator itr;
itr = $1->begin();
for( itr; itr != $1->end(); itr++ )
{
zval* tmp;
STF::MyOtherClass * res = new STF::MyOtherClass( *itr );
MAKE_STD_ZVAL( tmp );
swig_type_info type = *$descriptor(STF::MyOtherClass*);
type.name = (char*)"_p_CustomNamespace\\MyOtherClass";
SWIG_SetPointerZval( tmp, res, &type, 2 );
add_next_index_zval( return_value, tmp );
}
}
Шаблон% that awoodland не работал у меня. Я думаю, что это, вероятно, потому, что я не ставил PHP-класс в другое пользовательское пространство имен. Вместо этого я сделал это вручную и передал в точный php-класс, который я хотел использовать.
Ответ 2
Вы почти там, но как и %include <std_vector.i>
вам также понадобится что-то вроде:
%template (MyVector) std::vector<MyOtherClass>;
Это инструктирует SWIG выставить векторы MyOtherClass
на целевой язык как тип, называемый MyVector
. Без этого SWIG не знает, для каких типов вы хотите создать экземпляр std::vector
, поэтому он сводится к обертке по умолчанию.
Боковое примечание:
Есть ли причина, по которой у вас есть const
в const std::vector<MyOtherClass> getList();
, когда это не ссылка? Я бы либо сделал ссылку, и сделал метод const
также (const std::vector<MyOtherClass>& getList() const;
), либо полностью отбросил const
, так как он ничего не делает.