====== PHP RFC: use Statement ======
* Version: 0.9
* Date: 2025-09-08
* Author: Seifeddine Gmati azjezz@carthage.software, Tim Düsterhus timwolla@php.net
* Status: Draft
* Implementation: https://github.com/php/php-src/compare/master...TimWolla:php-src:block-scope
===== Introduction =====
This RFC proposes the introduction of the use statement, a new language construct for managing temporary variables and resources. It allows developers to define a block or a statement in which one or more variables are in scope. Upon statement completion, these variables are automatically and reliably unset, triggering their destructors and releasing any held resources.
This construct addresses several recurring challenges in PHP. Developers often need to ensure that resources like file handles are properly disposed of, especially when exceptions occur. Additionally, controlling variable scope is a frequent source of subtle bugs, such as the classic foreach-by-reference issue, where variables leak out of loops. Manually managing this with verbose try-finally blocks or error-prone unset() calls clutters code and reduces clarity.
The use statement provides a single, elegant solution to these common problems. By adopting a feature that has proven its value in other ecosystems, like Python’s ''with'' or C#’s ''using'', PHP can offer a safer and more readable way to write robust, maintainable code.
pool->getConnection()) {
$con->execute('UPDATE users SET last_seen = NOW() WHERE id = ?', $id);
}
// $con is now unset and the connection is returned to the pool.
assert(!isset($connection));
===== Proposal =====
We propose a new use() statement. It takes a list of variable declarations and executes a subsequent statement within a new, temporary scope. Upon completion of that statement—whether normally, through an exception, or a return—all variables declared in the use() list are automatically unset.
This feature provides immense value, particularly for modern applications built on long-lived servers, where disciplined and immediate resource cleanup is not just a best practice, but a necessity for stability and performance. By desugaring to a try-finally block internally, it provides a zero-cost abstraction that is both safe and highly ergonomic, eliminating the need for verbose manual cleanup.
For example, the following code:
*/
Is semantically equivalent to:
*/
} finally {
unset($a, $c);
}
This guarantees that objects are destructed and resources are freed immediately upon exiting the scope, rather than waiting for the function to end or for the garbage collector to run.
The full syntax is defined as follows:
::= "use" "(" ")"
::= { "," }
::= ( "=" ) |
==== Examples ====
Simple example:
Example showing an edge case (solving the foreach reference bug):
int(2) [1]=> int(4) [2]=> int(6) }
Example showing reliable resource management:
lock(LockType::Shared),
) {
$content = $file->readAll();
// Do work with the file...
return $content;
}
// The file lock is released here, immediately after it's no longer needed,
// which is crucial in high-concurrency environments.
}
===== Backward Incompatible Changes =====
None. The use keyword is being reused in a new context. The parser can unambiguously distinguish this construct from existing uses of use (for traits, namespace imports, and closures) based on the syntax that follows.
===== Proposed PHP Version(s) =====
Next PHP 8.x
===== RFC Impact =====
==== To the Ecosystem ====
* IDEs, LSPs, and Static Analyzers: Will need updates to understand the new scoping rules. This will enable them to provide correct autocompletion and error analysis, correctly identifying when a variable is out of scope.
* Auto-Formatters and Linters: Will require updates to support the new syntax.
==== To Existing Extensions ====
None.
==== To SAPIs ====
None.
===== Open Issues =====
The final behavior regarding pre-existing variables is subject to discussion on the mailing list before the vote begins. The key question is: what should happen if a variable declared in use() already exists in the outer scope?
* Option A (Unset): The variable is shadowed inside the use block and is unconditionally unset upon exit. Any previous value is lost. This is the current implementation in the PoC.
* Option B (Restore): The variable's original value is saved before entering the use block and restored upon exit. This would create a true block scope that does not affect the outer scope.
===== Future Scope =====
This RFC lays the foundation for explicit resource management in PHP. Future proposals could build upon it
* Introducing a Disposable interface (similar to C#'s IDisposable) to allow objects to define custom, explicit cleanup logic that is automatically called by use.
* Extending the use statement to support other resource management patterns.
===== Voting Choices =====
This RFC will have a single vote on whether to accept the feature in principle. The behavior for pre-existing variables (Open Issues) will be finalized based on mailing list discussion before the vote starts. A 2/3 majority is required.
* Yes
* No
* Abstain
===== Patches and Tests =====
A proof-of-concept implementation using the `unset` behavior is available at:
https://github.com/php/php-src/compare/master...TimWolla:php-src:block-scope
===== Implementation =====
After the RFC is implemented, this section should contain:
* The version(s) it was merged into
* A link to the git commit(s)
* A link to the PHP manual entry for the feature
===== References =====
* [[https://docs.python.org/3/reference/compound_stmts.html#the-with-statement|Python’s with statement]]
* [[https://docs.hhvm.com/hack/statements/using|Hack’s using statement]]
* [[https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using|C#’s using statement]]
===== Rejected Features =====
None.