PHP variables under the hood
Tags: php, variables, structures, pointers
Published: 2019-12-18 12:50:13

---
title: PHP variables under the hood
published: true
description: We all know how to create a variable, how to get the value of a variable, and how to take a reference to a variable. Let's have a learn what happens in the interpreter when you change the value of a variable? Or when you delete it? How are the types of variables implemented?
tags: php, variables, structures, pointers
series: php
canonical_url: https://blog.larapulse.com/php/variables-under-the-hood
cover_image: https://thepracticaldev.s3.amazonaws.com/i/650i4xq5py9wbvnke3zy.png
---


Variables in PHP are some containers that store the type of the variable, its value, the amount of referring variables to this container, and the flag - whether this variable is referenced.

![PHP variables under the hood](https://thepracticaldev.s3.amazonaws.com/i/n3ikl4kmnerkmunpu3su.png)

### Structures and Pointers

**Structures** are very similar to classes, but they can not have methods, just data, pointers to data and pointers to functions. Declaring a structure in C, you define the data type. And when defining a variable, you can write the name of this structure in place of the type of that variable, like so:

```c
my_super_struct super_struct_instance;
```

**Pointers** are like variables, but their values store an address in memory. Reference variables behave like dereferenced pointers, that means they access values of the pointer. Let's look at an example:

```c 
// defining pointer `foo`, that will points to the variable with `int` type
int *foo;
// defining variable with `int` type
int bar = 3;

// taking reference to variable `bar` and assigning it to pointer.
// `foo` stores memory address, where `bar` stores
foo = &bar;

// with an asterisk we dereference the pointer (take the value at its address) and increment the value
(*foo)++;

// we increment the pointer itself, that means the pointer will refer at another value
foo++;
```

![Dealing with pointers](https://thepracticaldev.s3.amazonaws.com/i/f1wdttptanh2d9m1up5d.png)

### Containers

The container is a structure called `zval` (short for **“Zend value”**), it represents an arbitrary PHP value and looks like this:

```c 
struct zval {
    zvalue_value value;
    zend_uchar type;
    zend_uchar is_ref;
    zend_ushort refcount;
};
```

As we can see, there is a value, a type, a flag and an amount of referring variables. PHP `zval` supports the following 8 types:

- `BOOL`
- `LONG` *(signed integer type)*
- `DOUBLE` *(used to store floating point numbers)*
- `STRING`
- `ARRAY`
- `OBJECT`
- `RESOURCE`
- `NULL`

`zvalue_value` is an `union`. A union is a special type that may have several members declarations of different types, but only one will be used. That how it defines:

```c 
typedef union _zvalue_value {
    long lval; // integer
    double dval; // float
    struct {
        char *val;
        int len;
    } str; // string
    HashTable *ht; // array
    zend_object obj; // object
} zvalue_value;
```

As a result, when you create a variable of this type, it will take in memory exactly as much as occupies the heaviest element of unions.

![PHP variable creation](https://thepracticaldev.s3.amazonaws.com/i/4l7d02iwfa5631htn8qe.png)

### Why do we need all this

First, let's figure out why we need **refcount**. That's very simple: when you assign to a variable value of another variable, they both refer to one `zval`, and `refcount` increments.

![2 variables refers to the same memory place](https://thepracticaldev.s3.amazonaws.com/i/pdep9xoab4qa8ism0cp1.png)

Now, if you change the value of one of these variables, PHP seeing the `refcount` greater than 1, will copy this `zval`, make the changes there, and your variable will point already to the new `zval`. It will look something like this:

<table width="100%">
<thead>
    <tr>
        <th>PHP</th>
        <th>Under the hood</th>
    </tr>
</thead>
<tbody>
    <tr>
        <td class="highlight">
<pre class="highlight php">
<code>$foo = "baz";
$bar = $foo;
</code></pre>
        </td>
        <td class="highlight">
<pre class="highlight c">
<code>bar,foo: {
    type: string,
    value:
        str:
            val: "baz"
            len: 3
    is_ref: 0
    refcount: 2
}
</code></pre>
        </td>
    </tr>
    <tr>
        <td class="highlight">
<pre class="highlight php">
<code>$bar .= "q";
</code></pre>
        </td>
        <td class="highlight">
<pre class="highlight c">
<code>foo: {
    type: string,
    value:
        str:
            val: "baz"
            len: 3
    is_ref: 0
    refcount: 1
}
bar: {
    type: string,
    value:
        str:
            val: "bazq"
            len: 4
    is_ref: 0
    refcount: 1
}
</code></pre>
        </td>
    </tr>
</tbody>
</table>

This technique is called **"copy on write"** and it allows to reduce memory consumption quite well. Also, `refcount` is needed for the **garbage collector**, which removes from memory all `zval`s, which have `refcount = 0`.

And what happens with references? And **`is_ref`** is working? That's very simple: if you create a reference from a variable, the is_ref flag becomes 1, and the above optimization for this zval will not be applied.

<table width="100%">
<thead>
    <tr>
        <th>PHP</th>
        <th>Under the hood</th>
    </tr>
</thead>
<tbody>
    <tr>
        <td class="highlight">
<pre class="highlight php"><code>$foo = "baz";
$bar = $foo;</code></pre>
        </td>
        <td>
<pre class="highlight c">
<code>bar,foo: {
    type: string,
    value:
        str:
            val: "baz"
            len: 3
    is_ref: 0
    refcount: 2
}
</code></pre>
        </td>
    </tr>
    <tr>
        <td class="highlight">
<pre class="highlight php">
<code>$baz = &$foo;</code></pre>
        </td>
        <td>
<pre class="highlight c">
<code>baz,foo: {
    type: string,
    value:
        str:
            val: "baz"
            len: 3
    is_ref: 1
    refcount: 2
}
bar: { // variable `bar` was allocated to a separate `zval`
    type: string,
    value:
        str:
            val: "baz"
            len: 3
    is_ref: 0
    refcount: 1
}
</code></pre>
        </td>
    </tr>
    <tr>
        <td class="highlight">
<pre class="highlight php">
<code>$qwe = $foo;</code></pre>
        </td>
        <td class="highlight">
<pre class="highlight c">
<code>baz,foo: {
    type: string,
    value:
        str:
            val: "baz"
            len: 3
    is_ref: 1
    refcount: 2
}
bar: {
    type: string,
    value:
        str:
            val: "baz"
            len: 3
    is_ref: 0
    refcount: 1
}
// this variable was also allocated to a separate `zval`
qwe: {
    type: string,
    value:
        str:
            val: "baz"
            len: 3
    is_ref: 0
    refcount: 1
}
</code></pre>
        </td>
    </tr>
</tbody>
</table>


***

> **Interesting in reading more about PHP? Follow [this link](https://blog.larapulse.com/php) to find more articles :wink:**