[RFC] Readonly Variables

php.internals

=?UTF-8?Q?Joshua_R=C3=BCsweg?=

189 days ago
Hi internals, I'd like to propose a new language feature for PHP: Readonly Variables. PHP currently has no way to declare a variable as immutable within a local or functional scope. This RFC proposes the readonly modifier for variables, which prevents reassignment after the initial declaration and results in an error on any attempt to do so. Key behaviors: - Reassignment and compound assignment operators are forbidden - Pass-by-reference is forbidden - unset() removes the readonly flag, allowing re-declaration - Readonly variables inside loops are permitted but limited to a single declaration - Scoping follows regular variable rules (function, method, closure boundaries) The RFC is available at: https://wiki.php.net/rfc/readonly-variables I'm looking forward to your feedback and discussion. Cheers, Joshua Rüsweg

Kamil Tekiela

189 days ago
On Mon, 23 Feb 2026 at 21:29, Joshua Rüsweg <josh@wcflabs.de> wrote:
> > Hi internals, > > I'd like to propose a new language feature for PHP: Readonly Variables. > > PHP currently has no way to declare a variable as immutable within a local or functional scope. This RFC proposes the readonly modifier for variables, which prevents reassignment after the initial declaration and results in an error on any attempt to do so. > > Key behaviors: > - Reassignment and compound assignment operators are forbidden > - Pass-by-reference is forbidden > - unset() removes the readonly flag, allowing re-declaration > - Readonly variables inside loops are permitted but limited to a single declaration > - Scoping follows regular variable rules (function, method, closure boundaries) > > The RFC is available at: > https://wiki.php.net/rfc/readonly-variables > > I'm looking forward to your feedback and discussion. > > Cheers, > Joshua Rüsweg
Hi Joshua, This is a very interesting proposal, but I feel like you haven't explained all your choices. I have some questions: 1. Why the use of readonly keyword? Why not const or some new keyword, e.g. locked. 2. Why does unset not remove the variable completely? If you want a feature to only unlock the variable then it probably needs a new keyword, e.g. unlock 3. What exactly does this mean: "Readonly variables inside loops are permitted but limited to a single declaration"? What does a single declaration look like? 4. How will this impact optimizer and JIT? 5. You said that readonly variables cannot be used with the global keyword. But what about readonly variables in global scope? Will they still behave like a typical global variable? 6. What exactly counts as a variable declaration? When is it a valid syntax to use this keyword? I don't think PHP had the concept of variable declaration until now. 7. What about compound variables such as arrays and objects? I would prefer starting with readonly parameters as I feel that would bring the most value. I think it would also be worthwhile to investigate a simpler syntax for define(). Regards, Kamil

Ben Ramsey

189 days ago
On 2/23/26 15:58, Kamil Tekiela wrote:
> On Mon, 23 Feb 2026 at 21:29, Joshua Rüsweg <josh@wcflabs.de> wrote: >> >> Hi internals, >> >> I'd like to propose a new language feature for PHP: Readonly Variables. >> >> PHP currently has no way to declare a variable as immutable within a local or functional scope. This RFC proposes the readonly modifier for variables, which prevents reassignment after the initial declaration and results in an error on any attempt to do so. >> >> Key behaviors: >> - Reassignment and compound assignment operators are forbidden >> - Pass-by-reference is forbidden >> - unset() removes the readonly flag, allowing re-declaration >> - Readonly variables inside loops are permitted but limited to a single declaration >> - Scoping follows regular variable rules (function, method, closure boundaries) >> >> The RFC is available at: >> https://wiki.php.net/rfc/readonly-variables >> >> I'm looking forward to your feedback and discussion. >> >> Cheers, >> Joshua Rüsweg > > Hi Joshua, > > This is a very interesting proposal, but I feel like you haven't > explained all your choices. I have some questions: > > 1. Why the use of readonly keyword? Why not const or some new keyword, > e.g. locked. > 2. Why does unset not remove the variable completely? If you want a > feature to only unlock the variable then it probably needs a new > keyword, e.g. unlock > 3. What exactly does this mean: "Readonly variables inside loops are > permitted but limited to a single declaration"? What does a single > declaration look like? > 4. How will this impact optimizer and JIT? > 5. You said that readonly variables cannot be used with the global > keyword. But what about readonly variables in global scope? Will they > still behave like a typical global variable? > 6. What exactly counts as a variable declaration? When is it a valid > syntax to use this keyword? I don't think PHP had the concept of > variable declaration until now. > 7. What about compound variables such as arrays and objects? > > I would prefer starting with readonly parameters as I feel that would > bring the most value. > I think it would also be worthwhile to investigate a simpler syntax > for define(). > > Regards, > Kamil
In addition to Kamil's questions, I'm concerned about the "taking a reference is forbidden" and "pass-by-reference is forbidden" requirements. Objects are references, whether or not using the `&` operator. According to this RFC, both of these would be forbidden: readonly $a = new Foo(); $b = $a; and: function modify(Foo $value): void {} readonly $a = new Foo(); modify($a); I said "according to this RFC," but the RFC doesn't mention object behavior with readonly at all, which I think might be an oversight. The only place it hints at allowing objects is in the examples with `new PDO()`. Is the idea to allow objects (and arrays) similar to how JavaScript handles these with `const`? That is, the objects and arrays themselves are mutable, but the variable name cannot be reassigned to a new object or array? Cheers, Ben

Tim Düsterhus

189 days ago
Hi Am 2026-02-24 01:45, schrieb Ben Ramsey:
> Objects are references, whether or not using the `&` operator.
This is false. Quoting from the PHP documentation at https://www.php.net/manual/en/language.oop5.references.php:
> One of the key-points of PHP OOP that is often mentioned is that > "objects are passed by references by default". This is not completely > true. […] In PHP, an object variable […] contains an object identifier > which allows object accessors to find the actual object.
-
> Is the idea to allow objects (and arrays) similar to how JavaScript > handles these with `const`? That is, the objects and arrays themselves > are mutable, but the variable name cannot be reassigned to a new object > or array?
The proposed semantics in the RFC are very clearly modeled after the existing behavior of `readonly` properties in PHP: Immutability of identity, which would be “cannot be reassigned”. I'd like to note here that arrays in PHP are values, thus they are immutable when stored in a readonly property (see https://3v4l.org/vS0ij). I expect the same from this RFC, but having array-semantics spelled out explicitly + an example certainly makes sense for clarity. Best regards Tim Düsterhus

=?UTF-8?Q?Joshua_R=C3=BCsweg?=

188 days ago
Hi Ben,
> On 24. Feb 2026, at 01:45, Ben Ramsey <ramsey@php.net> wrote: > > According to this RFC, both of these would be forbidden: > > readonly $a = new Foo(); > $b = $a;
As Tim already clarified, there is a common misconception about how PHP handles objects internally. In PHP, objects are not passed by reference in the sense of the `&` operator, but via an object identifier. This means that `$b = $a` simply copies the object identifier, not a reference to the variable itself, and is therefore perfectly valid: ``` <?php readonly $a = new Foo(); $b = $a; ``` The readonly flag only prevents re-assignment of `$a` itself. The `&` operator, on the other hand, would create a true reference to the variable `$a`, which would allow `$a` to be modified indirectly through `$b`, effectively circumventing the readonly flag. This is why taking a reference of a readonly variable is forbidden. I hope this clears up the concern.
> and: > > function modify(Foo $value): void {} > readonly $a = new Foo(); > modify($a); > > I said "according to this RFC," but the RFC doesn't mention object behavior with readonly at all, which I think might be an oversight. The only place it hints at allowing objects is in the examples with `new PDO()`. > > Is the idea to allow objects (and arrays) similar to how JavaScript handles these with `const`? That is, the objects and arrays themselves are mutable, but the variable name cannot be reassigned to a new object or array?
Regarding your question about object and array behavior: you are correct that the RFC did not explicitly document this, which was indeed an oversight on my part. As already mentioned above, the variable binding is immutable, meaning `$a` cannot be reassigned to a different object, but the internal state of the object can still be modified. This is also consistent with how the readonly attribute behaves for class properties: ``` <?php readonly $a = new Foo(); $a->value = "foo"; // Valid: modifying the object's internal state is allowed $a = new Foo(); // Error: Cannot re-assign readonly variable ``` For arrays, however, the behavior differs from JavaScript. In PHP, arrays are value types with copy-on-write semantics, not reference types. This means that a readonly array is fully immutable, as neither the array itself nor its elements can be modified after the initial assignment: ``` <?php readonly $arr = [1, 2, 3]; $arr[] = 4; // Error: Cannot re-assign readonly variable $arr[0] = 99; // Error: Cannot re-assign readonly variable ``` I have added explicit examples for both objects and arrays to the RFC to make this behavior clear. I appreciate you flagging this. (I apologize for the duplicate email, Ben. The first attempt was sent from an incorrect address and did not go through properly.) Cheers, Joshua Rüsweg

Alexandru Pătrănescu

189 days ago
On Tue, 24 Feb 2026, 00:00 Kamil Tekiela, <tekiela246@gmail.com> wrote:
> On Mon, 23 Feb 2026 at 21:29, Joshua Rüsweg <josh@wcflabs.de> wrote: > > > > Hi internals, > > > > I'd like to propose a new language feature for PHP: Readonly Variables. > > > > PHP currently has no way to declare a variable as immutable within a > local or functional scope. This RFC proposes the readonly modifier for > variables, which prevents reassignment after the initial declaration and > results in an error on any attempt to do so. > > > > The RFC is available at: > > https://wiki.php.net/rfc/readonly-variables > > > > I'm looking forward to your feedback and discussion. > > > > Cheers, > > Joshua Rüsweg > > Hi Joshua, > > This is a very interesting proposal, but I feel like you haven't > explained all your choices. I have some questions: > > 1. Why the use of readonly keyword? Why not const or some new keyword, > e.g. locked. > > I would prefer starting with readonly parameters as I feel that would > bring the most value. > I think it would also be worthwhile to investigate a simpler syntax > for define(). > >
Hi Kamil, Joshua, I wrote on this topic in the past: https://news-web.php.net/php.internals/126909 and I think we already cannot use readonly and final for parameter, as that conflicts with constructor parameter promotion:
> if we ever decide to use the final modifier for a
parameter, it would not be possible.
> it is already not possible to use the readonly modifier for a parameter
because of this I think that using const keyword might be one of the best options.
-- Alex

=?UTF-8?Q?Joshua_R=C3=BCsweg?=

189 days ago
Hello Kamil,
> On 23. Feb 2026, at 22:58, Kamil Tekiela <tekiela246@gmail.com> wrote: > > 1. Why the use of readonly keyword? Why not const or some new keyword, > e.g. locked.
I spent a long time thinking about the right keyword. In an early stage of development I chose `const`, as it is already used in this way in JavaScript, for example. However, the further I developed the feature and the more feedback I gathered from others, the more I gravitated towards `readonly`. The `readonly` keyword is already used in PHP for class properties and serves exactly the same purpose: declaring variables as immutable. Reusing `readonly` for variables is therefore consistent with existing PHP semantics. The `const` keyword, on the other hand, has fundamentally different semantics in PHP. A `const` declaration at the top level defines a globally accessible constant, and inside a class it defines a class constant. This is quite different from a locally scoped immutable variable, and using const for this feature would likely cause confusion for PHP developers who are already familiar with its existing meaning. Introducing an entirely new keyword for this purpose, such as `locked`, would in my opinion be counterproductive, as it could be unintuitive for developers who are already familiar with `readonly` and its meaning in PHP.
> 2. Why does unset not remove the variable completely? If you want a > feature to only unlock the variable then it probably needs a new > keyword, e.g. unlock
Thank you for pointing that out, as I apparently expressed myself ambiguously in the RFC. `unset()` behaves exactly as it does for regular variables: it removes the variable entirely. The only additional effect is that the `readonly` flag is cleared along with it, meaning the variable name can subsequently be reused with a new assignment, without the `readonly` flag. I have updated the RFC to make this behavior more explicit. Regarding the idea of a dedicated unlock mechanism: I don't think this is necessary, and I honestly don't see a practical use case for it. If a variable needs to be modified after its initial assignment, it simply should not be declared as readonly in the first place.
> 3. What exactly does this mean: "Readonly variables inside loops are > permitted but limited to a single declaration"? What does a single > declaration look like?
A readonly variable declared inside a loop is exposed to the outer scope, just like any other variable in PHP. This means that on the second iteration, PHP would attempt to re-assign an already initialized readonly variable, which results in a fatal error. A "single declaration" therefore means that the readonly variable can only be initialized once throughout the entire execution of the loop, not once per iteration. I hope this clarifies the behavior. Please let me know if you have any further questions.
> 4. How will this impact optimizer and JIT?
Thank you for raising this point. I have not yet investigated the impact on the optimizer and JIT, as the current implementation is an initial proof of concept intended to gather feedback from the community. I will definitely look into this before the voting phase and investigate whether and how readonly variables can be leveraged for potential optimizations. I will report back with my findings.
> 5. You said that readonly variables cannot be used with the global > keyword. But what about readonly variables in global scope? Will they > still behave like a typical global variable?
I am not entirely sure what you mean by "typical global variable behavior", so I will try to address what I believe you are asking. If your question is whether a readonly variable declared in the global scope can be imported into a function via the `global` statement, the answer is no. Importing a readonly variable via `global` is forbidden and results in an error. If you are asking whether readonly variables declared in the global scope are automatically accessible in function scopes, the answer is also no. Readonly variables follow the same scoping rules as regular variables, meaning they are not automatically available inside functions, just as regular variables are not. If you meant something else entirely, please feel free to clarify and I will be happy to address it.
> 6. What exactly counts as a variable declaration? When is it a valid > syntax to use this keyword? I don't think PHP had the concept of > variable declaration until now.
By "declaration" I simply mean a regular variable assignment prefixed with the readonly keyword: ``` <?php readonly $foo = "bar”; ``` You are right that PHP has not had a formal concept of variable declaration until now. The readonly keyword in this context is purely a modifier on a standard assignment statement, signaling that the variable cannot be re-assigned after its initial value has been set. Any valid assignment expression can be used as the initial value, including object instantiation, function calls, or scalar values.
> 7. What about compound variables such as arrays and objects?
The behavior differs depending on the type of value assigned to a readonly variable. For arrays, the entire array is immutable. This means that neither the array itself nor its elements can be modified after the initial assignment: ``` <?php readonly $arr = [1, 2, 3]; $arr[] = 4; // Error: Cannot re-assign readonly variable $arr[0] = 99; // Error: Cannot re-assign readonly variable ``` For objects, the behavior is consistent with how readonly works for class properties: the variable binding is immutable, meaning the object reference cannot be replaced with a different object. However, the internal state of the object itself can still be modified: ``` <?php readonly $obj = new stdClass(); $obj->value = "changed"; // Valid: modifying the object's internal state is allowed $obj = new stdClass(); // Error: Cannot re-assign readonly variable ``` I have added examples for both cases to the RFC to make this behavior explicit.
> I would prefer starting with readonly parameters as I feel that would > bring the most value.
I find the idea of readonly parameters interesting and have already given it some thought. However, it is out of scope for this RFC, as I wanted to keep the initial proposal focused and manageable. I have already mentioned it in the Future Scope section of the RFC as a potential natural extension that could be addressed in a separate RFC in the future.
> I think it would also be worthwhile to investigate a simpler syntax > for define().
It is worth noting that PHP already provides two ways to define global constants: `define()` and the `const` keyword. Both serve a different purpose than readonly variables, as they are globally accessible and not scoped to a local or functional context. See: https://3v4l.org/1r6gk Cheers, Joshua Rüsweg

Larry Garfield

188 days ago
On Tue, Feb 24, 2026, at 12:52 PM, Joshua Rüsweg wrote:
>> I would prefer starting with readonly parameters as I feel that would >> bring the most value. > > I find the idea of readonly parameters interesting and have already > given it some thought. However, it is out of scope for this RFC, as I > wanted to keep the initial proposal focused and manageable. I have > already mentioned it in the Future Scope section of the RFC as a > potential natural extension that could be addressed in a separate RFC > in the future.
A slight tangent here, but what would readonly parameters do? If you pass something by value, then already you cannot modify the value in the caller. If the value is large, it's already kept efficient by copy-on-write. If you pass by reference, then presumably you *want* to modify the value in the caller. If the value is an object, then as already discussed, its internals are mutable either way so you gain little, but the function cannot change the identity in the caller anyway. So I don't see what readonly parameters would even accomplish. The thing they accomplish in JS or Java or C simply doesn't apply in PHP. I'm still undecided at the moment on readonly variables. --Larry Garfield

Kamil Tekiela

188 days ago
On Tue, 24 Feb 2026 at 19:32, Larry Garfield <larry@garfieldtech.com> wrote:
> > On Tue, Feb 24, 2026, at 12:52 PM, Joshua Rüsweg wrote: > > >> I would prefer starting with readonly parameters as I feel that would > >> bring the most value. > > > > I find the idea of readonly parameters interesting and have already > > given it some thought. However, it is out of scope for this RFC, as I > > wanted to keep the initial proposal focused and manageable. I have > > already mentioned it in the Future Scope section of the RFC as a > > potential natural extension that could be addressed in a separate RFC > > in the future. > > A slight tangent here, but what would readonly parameters do? > > If you pass something by value, then already you cannot modify the value in the caller. If the value is large, it's already kept efficient by copy-on-write. > > If you pass by reference, then presumably you *want* to modify the value in the caller. > > If the value is an object, then as already discussed, its internals are mutable either way so you gain little, but the function cannot change the identity in the caller anyway. > > So I don't see what readonly parameters would even accomplish. The thing they accomplish in JS or Java or C simply doesn't apply in PHP. > > I'm still undecided at the moment on readonly variables. > > --Larry Garfield
A readonly parameter would mean that it would be impossible to reuse the variable within the function for something else. It's not uncommon for a function to preprocess the argument and still make use of the original value. A readonly modifier would prevent accidental overwrite. function foo(string|array $data) { if (is_string($data) ) { $data = [$data]; // Original argument lost } // .... return is_string($data) ? $result : [$result]; )

Kamil Tekiela

188 days ago
Thanks for the replies.
> > 3. What exactly does this mean: "Readonly variables inside loops are > > permitted but limited to a single declaration"? What does a single > > declaration look like? > > A readonly variable declared inside a loop is exposed to the outer scope, just like any other variable in PHP. This means that on the second iteration, PHP would attempt to re-assign an already initialized readonly variable, which results in a fatal error. A "single declaration" therefore means that the readonly variable can only be initialized once throughout the entire execution of the loop, not once per iteration.
So does that mean that it can only be used within a loop if that loop only has a single iteration or that the assignment is guarded by some condition? $var = null; while(true) { if ($var === null) { readonly $var = 42; } }
> > 5. You said that readonly variables cannot be used with the global > > keyword. But what about readonly variables in global scope? Will they > > still behave like a typical global variable? > > I am not entirely sure what you mean by "typical global variable behavior", so I will try to address what I believe you are asking. > If your question is whether a readonly variable declared in the global scope can be imported into a function via the `global` statement, the answer is no. Importing a readonly variable via `global` is forbidden and results in an error. > If you are asking whether readonly variables declared in the global scope are automatically accessible in function scopes, the answer is also no. Readonly variables follow the same scoping rules as regular variables, meaning they are not automatically available inside functions, just as regular variables are not. > If you meant something else entirely, please feel free to clarify and I will be happy to address it.
I meant using $GLOBALS. readonly $var = 42; function foo() { $GLOBALS['foo'] = 'bar'; } foo(); var_dump($foo);
> > 6. What exactly counts as a variable declaration? When is it a valid > > syntax to use this keyword? I don't think PHP had the concept of > > variable declaration until now. > > By "declaration" I simply mean a regular variable assignment prefixed with the readonly keyword: > > ``` > <?php > readonly $foo = "bar”; > ``` > > You are right that PHP has not had a formal concept of variable declaration until now. The readonly keyword in this context is purely a modifier on a standard assignment statement, signaling that the variable cannot be re-assigned after its initial value has been set. Any valid assignment expression can be used as the initial value, including object instantiation, function calls, or scalar values.
Right, but if PHP users have never thought about variable declaration, then it might be confusing for them to understand when it is legal to use this keyword. For example, you said that array destructuring is not supported but for me it's a regular variable assignment. It seems that assignment within a loop is also not allowed, but that doesn't seem to be clearly specified in the RFC. while(readonly $arr = $pdoStmt->fetch()) {} // Is this allowed assuming it only iterates once? foreach($arr as readonly $element) {} // This is forbidden, correct? for(readonly $foo; ; ) {} // Is this allowed? if(readonly $val = foobar()) {} // This is a regular variable assignment, is this allowed? What about array vivification? readonly $arr[] = 42; Or a declaration with a warning: readonly $i++; What about a slightly more complex variable assignment? $arr = [readonly $var = 42]; // or readonly $var1 = $var2 = 42; // or foobar(readonly $baz = 42); // or $foo = 'bar'; readonly $$foo = 42; Regards, Kamil