title: Details of PHP 7.4 Reference Counting of Zvals
body: <p>I have some points of clarification based on reading the internal implementations for zvals described here <a href="https://www.npopov.com/2015/05/05/Internal-value-representation-in-PHP-7-part-1.html" rel="nofollow noreferrer">Internal value representation in PHP 7 - Part 1</a> and <a href="https://www.npopov.com/2015/06/19/Internal-value-representation-in-PHP-7-part-2.html" rel="nofollow noreferrer">Internal value representation in PHP 7 - Part 2</a>.</p>
  <p>Before explaining my confusion in detail, I think it can be summed up by:</p>
  <p>(i) I do not see why object reference counting differs from that of arrays and strings</p>
  <p>(ii) why reference counting for strings differs from that of arrays.</p>
  <p>From what I understand, for &quot;complex&quot; data types like strings, arrays, and objects, those entities are reference counted types (in PHP 7.4).</p>
  <ul>
  <li>Within the _zval_struct class, there is member to track its type and a member of type zend_value, which is a union.</li>
  <li>Members of this union include pointers to zend_array, zend_object, zend_string, zend_reference</li>
  <li>The zend_array and the likes internally store a reference count and  other internals necessary for functionality</li>
  </ul>
  <p>1 So based on this simplistic view, I would imagine the reference counting for arrays, strings, and objects in PHP are the same, but it appears not to be the case. Can someone explain where this (apparently) overly simplistic view falls apart?</p>
  <p>I used the 'debug_zval_dump' function to count references (I do not have privileges to install xdebug to use 'xdebug_debug_zval'). In my subsequent analysis, I am assuming that the function's own parameter can influence the reference counts displayed.</p>
  <p>2 For objects, the following counts make sense to me, but it would be great to have confirmation.</p>
  <pre><code>class Foo{}
  $a = new Foo();
  debug_zval_dump($a); // #1: $a refcount = 2 -- and assume this is run after each line of code for each variable
  $b = $a; // #2: $a, $b refcount = 3
  $c = &amp;$a; // #3: $a, $b, and $c refcount = 3
  $a = new Foo(); // #4 $a, $b, and $c refcount = 2
  </code></pre>
  <p>Just to be clear: every time a variable is defined or updated, I pass all existing variables to debug_zval_dump in a PHP 7.4 engine. That's what the refcounts refer to. I'm just saving space.</p>
  <p>#1: There are two _zval_structs pointing to the object (one is the function parameter).</p>
  <p>#2: There are three _zval_structs pointing to the object (counting the function parameter)</p>
  <p>#3: The function parameter, $b, and a zend_reference (shared by $a and $c) point to the object</p>
  <p>#4: $a and $c refer to the same object through a common zend_reference (plus the function parameter) and $b and the function parameter refer to the same object.</p>
  <p>Is this counting wrong? Please correct me if so. Otherwise, we move to the more confusing items:</p>
  <p>3 Arrays:</p>
  <pre><code>$a=[]; // #1: $a refcount = 1
  $b=$a; // #2: $a, $b refcount = 1
  $c=&amp;$a; // #3: $a, $b, and $c refcount = 1
  $a[]=0; // #4: $a and $c refcount = 2, $b refcount = 1 
  </code></pre>
  <p>I would expect the same numbers as for 2.#1-#4 and that's not what what we get. This appears to be at odds with the PHP article linked to as, I would expect something more like the following at #4:</p>
  <p>$a, $c -&gt; zend_reference1(refcount=2) -&gt; zend_array2(refcount=2,value=[0])</p>
  <p>$parameter -------------------------------^</p>
  <p>$b, $parameter                       -&gt;        zend_array1(refcount=2,value=[])</p>
  <p>4 There is then yet different counting for strings.</p>
  <pre><code>$a=''; // #1: $a refcount = 1
  $b=$a; // #2: $a, $b refcount = 1
  $c=&amp;$a; // #3: $a, $b, and $c refcount = 1
  $a='foo'; // #4: $a, $b, and $c refcount = 1
  </code></pre>
  <p>I would have the same diagram here as for 3.</p>
  <p>What details am I overlooking for this reference counting?</p>
  <p>5 As a bonus, what happens when a reference is made to a number now? For example</p>
  <pre><code>$a=0;
  $b=&amp;$a; // $a, b -&gt; zend_reference(refcount=2) -&gt; zend_value(value=0)
  </code></pre>
  <p>Is the comment diagram correct, assuming that zend_value is stack based (since numeric values are not reference counted)?</p>