1*6777b538SAndroid Build Coastguard Worker 2*6777b538SAndroid Build Coastguard Worker# Refcounting Tips 3*6777b538SAndroid Build Coastguard Worker 4*6777b538SAndroid Build Coastguard WorkerOne of the trickiest parts of the C extension for PHP is getting the refcounting 5*6777b538SAndroid Build Coastguard Workerright. These are some notes about the basics of what you should know, 6*6777b538SAndroid Build Coastguard Workerespecially if you're not super familiar with PHP's C API. 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard WorkerThese notes cover the same general material as [the Memory Management chapter of 9*6777b538SAndroid Build Coastguard Workerthe PHP internal's 10*6777b538SAndroid Build Coastguard Workerbook](https://www.phpinternalsbook.com/php7/zvals/memory_management.html), but 11*6777b538SAndroid Build Coastguard Workercalls out some points that were not immediately clear to me. 12*6777b538SAndroid Build Coastguard Worker 13*6777b538SAndroid Build Coastguard Worker## Zvals 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard WorkerIn the PHP C API, the `zval` type is roughly analogous to a variable in PHP, eg: 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker```php 18*6777b538SAndroid Build Coastguard Worker // Think of $a as a "zval". 19*6777b538SAndroid Build Coastguard Worker $a = []; 20*6777b538SAndroid Build Coastguard Worker``` 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard WorkerThe equivalent PHP C code would be: 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker```c 25*6777b538SAndroid Build Coastguard Worker zval a; 26*6777b538SAndroid Build Coastguard Worker ZVAL_NEW_ARR(&a); // Allocates and assigns a new array. 27*6777b538SAndroid Build Coastguard Worker``` 28*6777b538SAndroid Build Coastguard Worker 29*6777b538SAndroid Build Coastguard WorkerPHP is reference counted, so each variable -- and thus each zval -- will have a 30*6777b538SAndroid Build Coastguard Workerreference on whatever it points to (unless its holding a data type that isn't 31*6777b538SAndroid Build Coastguard Workerrefcounted at all, like numbers). Since the zval owns a reference, it must be 32*6777b538SAndroid Build Coastguard Workerexplicitly destroyed in order to release this reference. 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard Worker```c 35*6777b538SAndroid Build Coastguard Worker zval a; 36*6777b538SAndroid Build Coastguard Worker ZVAL_NEW_ARR(&a); 37*6777b538SAndroid Build Coastguard Worker 38*6777b538SAndroid Build Coastguard Worker // The destructor for a zval, this must be called or the ref will be leaked. 39*6777b538SAndroid Build Coastguard Worker zval_ptr_dtor(&a); 40*6777b538SAndroid Build Coastguard Worker``` 41*6777b538SAndroid Build Coastguard Worker 42*6777b538SAndroid Build Coastguard WorkerWhenever you see a `zval`, you can assume it owns a ref (or is storing a 43*6777b538SAndroid Build Coastguard Workernon-refcounted type). If you see a `zval*`, which is also quite common, then 44*6777b538SAndroid Build Coastguard Workerthis is *pointing to* something that owns a ref, but it does not own a ref 45*6777b538SAndroid Build Coastguard Workeritself. 46*6777b538SAndroid Build Coastguard Worker 47*6777b538SAndroid Build Coastguard WorkerThe [`ZVAL_*` family of 48*6777b538SAndroid Build Coastguard Workermacros](https://github.com/php/php-src/blob/4030a00e8b6453aff929362bf9b25c193f72c94a/Zend/zend_types.h#L883-L1109) 49*6777b538SAndroid Build Coastguard Workerinitializes a `zval` from a specific value type. A few examples: 50*6777b538SAndroid Build Coastguard Worker 51*6777b538SAndroid Build Coastguard Worker* `ZVAL_NULL(&zv)`: initializes the value to `null` 52*6777b538SAndroid Build Coastguard Worker* `ZVAL_LONG(&zv, 5)`: initializes a `zend_long` (integer) value 53*6777b538SAndroid Build Coastguard Worker* `ZVAL_ARR(&zv, arr)`: initializes a `zend_array*` value (refcounted) 54*6777b538SAndroid Build Coastguard Worker* `ZVAL_OBJ(&zv, obj)`: initializes a `zend_object*` value (refcounted) 55*6777b538SAndroid Build Coastguard Worker 56*6777b538SAndroid Build Coastguard WorkerNote that all of our custom objects (messages, repeated fields, descriptors, 57*6777b538SAndroid Build Coastguard Workeretc) are `zend_object*`. 58*6777b538SAndroid Build Coastguard Worker 59*6777b538SAndroid Build Coastguard WorkerThe variants that initialize from a refcounted type do *not* increase the 60*6777b538SAndroid Build Coastguard Workerrefcount. This makes them suitable for initializing from a newly-created object: 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker```c 63*6777b538SAndroid Build Coastguard Worker zval zv; 64*6777b538SAndroid Build Coastguard Worker ZVAL_OBJ(&zv, CreateObject()); 65*6777b538SAndroid Build Coastguard Worker``` 66*6777b538SAndroid Build Coastguard Worker 67*6777b538SAndroid Build Coastguard WorkerOnce in a while, we want to initialize a `zval` while also increasing the 68*6777b538SAndroid Build Coastguard Workerreference count. For this we can use `ZVAL_OBJ_COPY()`: 69*6777b538SAndroid Build Coastguard Worker 70*6777b538SAndroid Build Coastguard Worker```c 71*6777b538SAndroid Build Coastguard Workerzend_object *some_global; 72*6777b538SAndroid Build Coastguard Worker 73*6777b538SAndroid Build Coastguard Workervoid GetGlobal(zval *zv) { 74*6777b538SAndroid Build Coastguard Worker // We want to create a new ref to an existing object. 75*6777b538SAndroid Build Coastguard Worker ZVAL_OBJ_COPY(zv, some_global); 76*6777b538SAndroid Build Coastguard Worker} 77*6777b538SAndroid Build Coastguard Worker``` 78*6777b538SAndroid Build Coastguard Worker 79*6777b538SAndroid Build Coastguard Worker## Transferring references 80*6777b538SAndroid Build Coastguard Worker 81*6777b538SAndroid Build Coastguard WorkerA `zval`'s ref must be released at some point. While `zval_ptr_dtor()` is the 82*6777b538SAndroid Build Coastguard Workersimplest way of releasing a ref, it is not the most common (at least in our code 83*6777b538SAndroid Build Coastguard Workerbase). More often, we are returning the `zval` back to PHP from C. 84*6777b538SAndroid Build Coastguard Worker 85*6777b538SAndroid Build Coastguard Worker```c 86*6777b538SAndroid Build Coastguard Worker zval zv; 87*6777b538SAndroid Build Coastguard Worker InitializeOurZval(&zv); 88*6777b538SAndroid Build Coastguard Worker // Returns the value of zv to the caller and donates our ref. 89*6777b538SAndroid Build Coastguard Worker RETURN_COPY_VALUE(&zv); 90*6777b538SAndroid Build Coastguard Worker``` 91*6777b538SAndroid Build Coastguard Worker 92*6777b538SAndroid Build Coastguard WorkerThe `RETURN_COPY_VALUE()` macro (standard in PHP 8.x, and polyfilled in earlier 93*6777b538SAndroid Build Coastguard Workerversions) is the most common way we return a value back to PHP, because it 94*6777b538SAndroid Build Coastguard Workerdonates our `zval`'s refcount to the caller, and thus saves us from needing to 95*6777b538SAndroid Build Coastguard Workerdestroy our `zval` explicitly. This is ideal when we have a full `zval` to 96*6777b538SAndroid Build Coastguard Workerreturn. 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard WorkerOnce in a while we have a `zval*` to return instead. For example when we parse 99*6777b538SAndroid Build Coastguard Workerparameters to our function and ask for a `zval`, PHP will give us pointers to 100*6777b538SAndroid Build Coastguard Workerthe existing `zval` structures instead of creating new ones. 101*6777b538SAndroid Build Coastguard Worker 102*6777b538SAndroid Build Coastguard Worker```c 103*6777b538SAndroid Build Coastguard Worker zval *val; 104*6777b538SAndroid Build Coastguard Worker if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &val) == FAILURE) { 105*6777b538SAndroid Build Coastguard Worker return; 106*6777b538SAndroid Build Coastguard Worker } 107*6777b538SAndroid Build Coastguard Worker // Returns a copy of this zval, adding a ref in the process. 108*6777b538SAndroid Build Coastguard Worker RETURN_COPY(val); 109*6777b538SAndroid Build Coastguard Worker``` 110*6777b538SAndroid Build Coastguard Worker 111*6777b538SAndroid Build Coastguard WorkerWhen we use `RETURN_COPY`, the refcount is increased; this is perfect for 112*6777b538SAndroid Build Coastguard Workerreturning a `zval*` when we do not own a ref on it. 113