Julie Applegate
Julie Applegate

Reputation: 11

trying to understand php's zvals

I'm trying to understand PHP's zvals. So consider the following code:

<?php
$randomByteString = 'abcd';

$val = 0;
for ($i = 0; $i < 4; ++$i) {
    $val |= ord($randomByteString[$i]) << ($i * 8);
}

echo $val;

It seems to me that a zval would be created for each of these statements:

Is that correct?

Upvotes: 1

Views: 216

Answers (1)

mystery
mystery

Reputation: 19513

Not quite. Let's go through it line-by-line, covering how PHP 5 would handle these zvals.

<?php
$randomByteString = 'abcd';

A new zval containing 'abcd' is created and now $randomByteString points to it.

Zval count so far: 1

$val = 0;

A new zval containing 0 is created and now $val points to it.

Zval count so far: 2

for ($i = 0; $i < 4; ++$i) {

The first time we run through this, we create a zval for 0 and point $i to it.

Comparing $i and 4 might create a boolean zval temporarily. My memory of what PHP 5 does here is fuzzy, it might not do this under-the-hood. It doesn't matter for our overall count though, because it'd be thrown away immediately.

Incrementing $i doesn't create a zval, it just changes the number inside the zval $i already points to.

Zval count so far: 3 (not including temporary zval as it was thrown away)

    $val |= ord($randomByteString[$i]) << ($i * 8);

Accessing $randomByteString[$i] will create a zval containing a single-byte string. Passing it to ord() will discard that zval and create a new zval containing an integer.

Multiplying it 8 by $i will create a new zval.

Left shifting our ord() result by our $i result will create a new zval and chuck away our two input zvals.

Finally, using |= with $val will change the value in $val and chuck away our left shift result. $val already exists so we just change the contents rather than making a new zval for it.

Zval count so far: 4

}

echo $val;

Echo won't create any zvals.

At the end of the script, you have 4 zvals around.

By the way, the zvals created for $i < 4, $randomByteString[$i], ($i * 8) and << are all temporary zvals: they don't cause new memory allocations, instead they're stored in a special area of memory used for temporary values. This means that there's no performance penalty for creating these temporary values. The other zvals (including ord() for some reason, function calls are inefficient), on the other hand, do require memory allocations.

Also, this is all just for PHP 5. PHP 7 handles zvals a lot more smartly, so that usually there's no separate memory allocations needed for them.

Upvotes: 3

Related Questions