Как использовать 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, так как он ничего не делает.