I'm writing a PHP extension in C++ which need to provide a function which
will take as a parameter a zval *. This zval * should, when the function
has completed its task, simply be returned unmodified. How do I accomplish
this? I've tried something like this:
return_value = v;
There are two problems here:
#1 return_value is just a parameter in the prototype:
void zif_my_func(int ht, zval *return_value, zval **return_value_ptr, zval
*this_ptr, int return_value_used TSRMLS_DC)
So when you set: return_value = v; You are in fact changing where
return_value points, but you're not doing anything to the contents of the
return_value zval that the calling scope (the engine) knows about. You're
just changing the local pointer to look at another address.
Using return_value_ptr you can both clean up the original memory allocated
for return_value, and change what the engine knows about return_value since
you have the pointer to the pointer which the engine uses:
/* Destroy old return_value (prevents leaks) */
zval_ptr_dtor(return_value_ptr);
/* Point return_value at the passed in val */
*return_value_ptr = v;
This brings us to the second problem:
#2 The refcount of v will have been temporarily increased by the engine when
it was placed on the parameter stack, however when the function exits, that
refcount will be decremented back down and there will be no refcount
associated with the copy stored in return_value. Long story short you need
to add ref the value when you assign it to a new container:
ZVAL_ADDREF(v);
zval_ptr_dtor(return_value_ptr);
*return_value_ptr = v;
Now for problem number 3 (What, you thought I'd stop at two?)
If v was an is_ref value, with a refcount of only 2 at the time of leaving
your internal function, and you're using PHP 5.0, the function return will
break the reference set. This is a known bug and is fixed in the 5.1
branch.
And problem #3a (PHP4 compatability)
PHP4 doesn't even have the return_value_ptr parameter so you can't even do
that stuff with it. What you can do is perform a deep copy on the value:
*return_value = *v;
zval_copy_ctor(return_value);
While it's less memory/cpu efficient, it is usable across all versions.
-Sara
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php