Podręcznik PHP
Poprzedni | Rozdział 32. Accepting Arguments | Następny

# Dealing with Arguments Passed by Reference

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 `zval`s 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 Przykład 32-3.

Przykład 32-3. Testing for referenced parameter passing.
    zval *parameter;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &parameter) == FAILURE)
        return;

    /* check for parameter being passed by reference */
    if (!PZVAL_IS_REF(*parameter)) {
    {
        zend_error(E_WARNING, "Parameter wasn't passed by reference");
        RETURN_NULL();
    }

    /* make changes to the parameter */
    ZVAL_LONG(*parameter, 10);

Poprzedni | Spis treści | Następny
Accessing Arguments | Początek rozdziału | Assuring Write Safety for Other Parameters