If your function accepts arguments passed by reference that you
intend to modify, you need to take some precautions.

What we didn't say yet is that under the circumstances presented so
far, you don't have write access to any zval containers
designating function parameters that have been passed to you. Of course, you
can change any zval containers that you created within
your function, but you mustn't change any zvals that refer to
Zend-internal data!

We've only discussed the so-called *_ex() API
so far. You may have noticed that the API functions we've used are
called zend_get_parameters_ex() instead of
zend_get_parameters(),
convert_to_long_ex() instead of
convert_to_long(), etc. The
*_ex() functions form the so-called new
"extended" Zend API. They give a minor speed increase over the old
API, but as a tradeoff are only meant for providing read-only
access.

Because Zend works internally with references, different variables
may reference the same value. Write access to a
zval container requires this container to contain
an isolated value, meaning a value that's not referenced by any
other containers. If a zval container were
referenced by other containers and you changed the referenced
zval, you would automatically change the contents
of the other containers referencing this zval
(because they'd simply point to the changed value and thus change
their own value as well).

zend_get_parameters_ex() doesn't care about
this situation, but simply returns a pointer to the desired
zval containers, whether they consist of references
or not. Its corresponding function in the traditional API,
zend_get_parameters(), immediately checks for
referenced values. If it finds a reference, it creates a new,
isolated zval container; copies the referenced data
into this newly allocated space; and then returns a pointer to the
new, isolated value.

This action is called zval separation
(or pval separation). Because the *_ex() API
doesn't perform zval separation, it's considerably faster, while
at the same time disabling write access.

To change parameters, however, write access is required. Zend deals
with this situation in a special way: Whenever a parameter to a function is
passed by reference, it performs automatic zval separation. This means that
whenever you're calling a function like
this in PHP, Zend will automatically ensure
that $parameter is being passed as an isolated value, rendering it
to a write-safe state:

my_function(&$parameter);

But this is not the case with regular parameters!
All other parameters that are not passed by reference are in a read-only
state.

This requires you to make sure that you're really working with a
reference - otherwise you might produce unwanted results. To check for a
parameter being passed by reference, you can use the macro
PZVAL_IS_REF. This macro accepts a zval*
to check if it is a reference or not. Examples are given in
in Example 48-3.