Data Creation

Now that you've seen how to pull data out of a zval, it's time to create some of your own. Although a zval could be simply declared as a direct variable at the top of a function, it would make the variable's data storage local and it would have to be copied in order to leave the function and reach userspace.

Because you will almost always want zvals that you create to reach userspace in some form, you'll want to allocate a block of memory for it and assign that block to a zval* pointer. Once again the "obvious" solution of using malloc(sizeof(zval)) is not the right answer. Instead you'll use another Zend macro: MAKE_STD_ZVAL(pzv). This macro will allocate space in an optimized chunk of memory near other zvals, automatically handle out-of-memory errors (which you'll explore further in the next chapter), and initialize the refcount and is_ref properties of your new zval.

Note

In addition to MAKE_STD_ZVAL(), you will often see another zval* creation macro used in PHP sources: ALLOC_INIT_ZVAL(). This macro only differs from MAKE_STD_ZVAL() in that it initializes the data type of the zval* to IS_NULL.

Once data storage space is available, it's time to populate your brand-new zval with some information. After reading the section on data storage earlier, you're probably all primed to use those Z_TYPE_P() and Z_SOMEVAL_P() macros to set up your new variable. Seems the "obvious" solution right?

Again, obviousness falls short!

Zend exposes yet another set of macros for setting zval* values. Following are these new macros and how they expand to the ones you're already familiar with.

ZVAL_NULL(pvz); Z_TYPE_P(pzv) = IS_NULL;

Although this macro doesn't provide any savings over using the more direct version, it's included for completeness.

ZVAL_BOOL(pzv, b); Z_TYPE_P(pzv) = IS_BOOL; Z_BVAL_P(pzv) = b ? 1 : 0; ZVAL_TRUE(pzv); ZVAL_BOOL(pzv, 1); ZVAL_FALSE(pzv); ZVAL_BOOL(pzv, 0);

Notice that any non-zero value provided to ZVAL_BOOL() will result in a truth value. This makes sense of course, because any non-zero value type casted to Boolean in userspace will exhibit the same behavior. When hardcoding values into internal code, it's considered good practice to explicitly use the value 1 for truth. The macros ZVAL_TRUE() and ZVAL_FALSE() are provided as a convenience and can sometimes lend to code readability.

ZVAL_LONG(pzv, l); Z_TYPE_P(pzv) = IS_LONG; Z_LVAL_P(pzv) = l; ZVAL_DOUBLE(pzv, d); Z_TYPE_P(pzv) = IS_DOUBLE; Z_DVAL_P(pzv) = d;

The basic scalar macros are as simple as they come. Set the zval's type, and assign a numeric value to it.

ZVAL_STRINGL(pzv,str,len,dup); Z_TYPE_P(pzv) = IS_STRING; Z_STRLEN_P(pzv) = len; if (dup) { Z_STRVAL_P(pzv) = estrndup(str, len + 1); } else { Z_STRVAL_P(pzv) = str; } ZVAL_STRING(pzv, str, dup); ZVAL _STRINGL(pzv, str, strlen(str), dup);

Here's where zval creation starts to get interesting. Strings, like arrays, objects, and resources, need to allocate additional memory for their data storage. You'll explore the pitfalls of memory management in the next chapter; for now, just notice that a dup value of 1 will allocate new memory and copy the string's contents, while a value of 0 will simply point the zval at the already existing string data.

ZVAL_RESOURCE(pzv, res); Z_TYPE_P(pzv) = IS_RESOURCE; Z_RESVAL_P(pzv) = res;

Recall from earlier that a resource is stored in a zval as a simple integer that refers to a lookup table managed by Zend. The ZVAL_RESOURCE() macro therefore acts much like the ZVAL_LONG() macro, but using a different type.

Категории