References Are NOT Pointers — CTF Edition
| Aspect | Pointer (C / C++) | Reference (PHP) |
|---|---|---|
| Storage | Variable that holds a memory address like 0x7fff... | Just another name bound to the same zval |
| After deletion | Dangling pointer — undefined behaviour, potential crash | All remaining aliases keep working perfectly |
| Arithmetic | Pointer arithmetic possible (ptr+1, ptr-2) | Impossible — no access to raw addresses |
| Memory management | Manual — you must call free() | Automatic — refcount GC handles everything |
Every PHP variable is backed internally by a zval (Zend Value Structure). A zval contains three key fields:
• value — the actual stored data
• refcount — how many names are currently bound to this zval
• is_ref — whether an explicit reference binding exists
When you write $b = &$a, no copy is made. Both names point to the same zval and refcount increments by 1.
When you call unset($a), refcount drops by 1 only. The zval is freed from memory only when refcount reaches exactly 0.
One of the most common hard-to-spot bugs in PHP production code:
A common misconception: "objects are passed by reference automatically." This is not accurate.
PHP passes an Object Identifier — an internal handle number. The identifier is copied, not the object itself.
So if you do $b = $a and mutate $b->x, it affects $a->x too because both identifiers resolve to the same object. But if you reassign $b = new Foo(), only $b's binding changes — $a is completely unaffected.
If you want a true reference to the variable slot itself: $b = &$a