advanced php language
Weak References
A weak reference lets code refer to an object without keeping that object alive. If the rest of the program stops strongly referencing the object, PHP can garbage-collect it and the weak reference will return null.
Weak references are specialist tooling. You may see them in caches, object metadata stores, event systems, proxy libraries, containers, and framework internals. Most business code should use normal object references.
Strong References Keep Objects Alive
A normal object variable keeps the object alive.
<?php
declare(strict_types=1);
final class User
{
public function __construct(
public string $email,
) {
}
}
$user = new User('ada@example.com');
$anotherReference = $user;
unset($user);
echo $anotherReference->email . PHP_EOL;
// Prints:
// ada@example.com
The object still exists because $anotherReference points to it.
WeakReference
WeakReference::create() creates a weak reference to an object. Calling get() returns the object while it is still alive, or null after it has been collected.
<?php
declare(strict_types=1);
final class User
{
public function __construct(
public string $email,
) {
}
}
$user = new User('ada@example.com');
$weak = WeakReference::create($user);
echo $weak->get()?->email . PHP_EOL;
unset($user);
gc_collect_cycles();
echo $weak->get() === null ? 'collected' : 'still alive';
echo PHP_EOL;
// Prints:
// ada@example.com
// collected
The weak reference did not keep the user object alive.
WeakMap
WeakMap stores values against object keys without keeping those object keys alive. When the object key is collected, the entry disappears.
<?php
declare(strict_types=1);
final class Request
{
}
$metadata = new WeakMap();
$request = new Request();
$metadata[$request] = ['started_at' => '10:00'];
echo count($metadata) . PHP_EOL;
unset($request);
gc_collect_cycles();
echo count($metadata) . PHP_EOL;
// Prints:
// 1
// 0
This is useful for attaching metadata to objects without modifying their classes and without leaking memory in long-running processes.
Why This Matters In Long-Running PHP
Traditional PHP request/response applications often exit after each request, so memory is released quickly. Long-running workers are different: queue workers, WebSocket servers, async runtimes, daemons, and test processes can stay alive for a long time.
If a long-running process stores normal references in a global cache or static array, objects may never be collected. Weak references can help avoid that in library-level code.
When Not To Use Weak References
Do not use weak references to avoid deciding ownership. If an object is needed for a business operation, use a normal reference and make the lifetime clear.
Weak references can make code harder to reason about because get() may return an object now and null later. That is useful for caches and metadata, but awkward for ordinary application logic.
What You Should Be Able To Do
After this lesson, you should be able to explain that weak references do not keep objects alive, use WeakReference::create(), recognise WeakMap, and understand why this is mainly useful in caches, metadata stores, and long-running processes.
For junior work, the practical skill is recognising weak references in framework or library code without mistaking them for normal ownership.
Practice
Practice: Observe A Weak Reference
Create a small PHP example that shows a weak reference becoming empty.
Task
Build:
- a simple object
- a
WeakReferenceto that object - output while the object is still strongly referenced
- output after unsetting the strong reference and collecting cycles
Use strict types. Keep the expected output in the PHP code block as printed lines or comments.
Check Your Work
Confirm:
get()returns the object before it is unset- the weak reference does not keep the object alive
get()returnsnullafter collection
Afterward, explain why this is useful for cache-like library code but uncommon in normal business logic.
Show solution
This solution shows that the weak reference can see the object while it exists but does not keep it alive.
<?php
declare(strict_types=1);
final class User
{
public function __construct(
public string $email,
) {
}
}
$user = new User('ada@example.com');
$weak = WeakReference::create($user);
echo $weak->get()?->email . PHP_EOL;
unset($user);
gc_collect_cycles();
echo $weak->get() === null ? 'collected' : 'still alive';
echo PHP_EOL;
// Prints:
// ada@example.com
// collected
This is useful for cache-like library code because metadata or cached values can disappear when the original object disappears. Normal business logic usually needs clear ownership, so a normal reference is easier to reason about.