#943 [php5] Function returning object always returns new object

closed-fixed
php (58)
5
2009-07-29
2008-09-05
Barry Cohen
No

I've been working with SWIG for Python, Perl and PHP5 and have found the following to be a problem on PHP5 only. Using SWIG 1.3.36.

Wrap the following C++ for php5:

== example.h ==

class Foo
{
public:
Foo() { i = 303; }
int get_i() { return i; }

Foo &update_i(Foo &f)
{
f.i *= 2;
return f;
}
private:
int i;
};

== example.i ==

%module example
%{
#include "example.h"
%}

%include "example.h"

The produced example.php then contains this update function:

class Foo {
-- snip --
function update_i($f) {
$r=Foo_update_i($this->_cPtr,$f);
return is_resource($r) ? new Foo($r) : $r;
}
}

As far as I can tell, the whole is_resource() thing is used because the function is returning an object. The problem is that $r is always a resource, so you always get a new Foo() back. Consequently, this PHP:

$b = new Foo();
print $b->get_i() . "\n";
$b = $b->update_i($b);
print $b->get_i() . "\n";

produces

303
303

rather than

303
606

as you would hope.

This may seem like a bit of a contrived example, but the same thing happens if you create a C++ vector of structs, e.g.

== example.h ==

struct foo
{
int bar;
};

== example.i ==

%module example
%rename(is_empty) empty;
%include "std_vector.i"

%{
#include "example.h"
%}

%template(v_foo) std::vector<foo>;

%include "example.h"

Again, the get() function in the v_foo class in example.php contains the is_resource() thing. This leads to the following PHP error:

$v = new v_Foo();
$foo = new foo();
$foo->bar = 123;
$v->push($foo);
print $v->size() . "\n";
print $v->get(0)->bar . "\n";

This prints:

1
0

rather than

1
123

as you would expect, because a new foo() is returned from v_foo->get().

The biggest problem for me at the moment is that I can't think of a sensible workaround without modifying the way the initial C++ works.

Thanks

Discussion

  • Olly Betts

    Olly Betts - 2008-09-18

    Creating the new PHP-side Foo object is OK as it's the wrapped C++ object which matters (at least while we don't support directors for PHP).

    Your example works if you explicitly define the copy constructor in example.h:

    Foo(const Foo&o) : i(o.i) {}

    Now I just need to figure out why...

     
  • Olly Betts

    Olly Betts - 2008-09-18
    • assigned_to: kruland --> olly
     
  • Olly Betts

    Olly Betts - 2008-10-01

    OK, so the issue seems to be that SWIG doesn't wrap an implicit copy ctor unless you use %copyctor or -copyctor equivalent.

    But the PHP backend isn't aware of this.

     
  • Olly Betts

    Olly Betts - 2009-07-29

    Hmm, well SVN trunk now generates C++ code which fails to compile for this example.

    I think this is fallout from the merge of vmiklos's PHP directors branch, so I've asked him to take a look.

     
  • Olly Betts

    Olly Betts - 2009-07-29

    Ah no, I was processing it without -c++, it does compile.

    Sadly still broken, though the output for the first example is now:

    303
    0

    Which I find harder to understand...

     
  • Olly Betts

    Olly Betts - 2009-07-29

    Right, the problem is that the odd assigning of the return value causes Zend to free $b. The memory gets zeroed, hence the zero.

    You can either remove pointless assignment to $b of the result of calling update_i(), or tell the proxy object that it doesn't own the C++ object temporarily, like so:

    <?
    include "example.php";
    $b = new Foo();
    print $b->get_i() . "\n";
    $b->thisown = 0;
    $b = $b->update_i($b);
    $b->thisown = 1;
    print $b->get_i() . "\n";

    The more complex case with the vector works fine with SVN trunk without any messing about.

    So closing this ticket now.

     
  • Olly Betts

    Olly Betts - 2009-07-29
    • status: open --> closed-fixed
     

Log in to post a comment.