[Pre-RFC] Null coalescing associative array elements

php.internals

Alexander Egorov

95 days ago
Greetings, internals! In my practice, it is a very common case when I need to create an associative array with varying structure, by that meaning that some fields in the array are optional and are set conditionally. And of all conditions the most frequent is checking for null-values: if the value is null, then this field should be omitted from the final result. Unfortunately, PHP currently does not offer any shorthand syntax for declaring such fields in a compact way. In most cases for each of such fields we need to have a dedicated "if", like: // $array is first filled with all required fields // Then we add all optional fields based on some condition if ($value !== null) { $array['field'] = $value; } This often leads to cumbersome code. My proposal, which already has a prototype implementation, is following. When declaring an associative array, add a new null-coalescing double arrow for the fields which should be omitted if the value is null: $array = [ 'field1' => $param1, 'field2' => $param2, 'field3' ?=> $param3, ]; In this case, if $param3 === null, the created array would only contain 'field1' and 'field2' from start, without the need to later get rid of 'field3'. This syntax will also allow more generalized conditions. For example, instead of: if ($someCondition) { $array['field'] = $value; } You could create such array from start, if you are OK with such code-style: $array = [ // other fields 'field' ?=> $someCondition ? $value : null, ]; The token '?=>' given here is mainly just an example, because the exact form should be discussed anyway (this one, as well as others, have pros and cons). So, before I create an RFC for this feature, I would like to get initial feedback: would this feature be welcome in general? Prototype implementation for it: https://github.com/Amegatron/php-src/tree/conditional-array-elements Or just the diff with current master: https://github.com/php/php-src/compare/master...Amegatron:php-src:conditional-array-elements This is still a prototype though, some additional work must be done of course, not counting the tests. A slightly bigger example: https://gist.github.com/Amegatron/06da8770e46e116b05f1c290cb0d56fc Looking forward to your feedback. Cheers, Alexander Egorov.

Larry Garfield

95 days ago
On Fri, May 29, 2026, at 4:31 AM, Alexander Egorov wrote:
> Greetings, internals! > > In my practice, it is a very common case when I need to create an > associative array with varying structure, by that meaning that some > fields in the array are optional and are set conditionally. And of all > conditions the most frequent is checking for null-values: if the value > is null, then this field should be omitted from the final result. > > Unfortunately, PHP currently does not offer any shorthand syntax for > declaring such fields in a compact way. In most cases for each of such fields > we need to have a dedicated "if", like: > > // $array is first filled with all required fields > // Then we add all optional fields based on some condition > if ($value !== null) { > $array['field'] = $value; > } > > This often leads to cumbersome code. > > My proposal, which already has a prototype implementation, is following. > When declaring an associative array, add a new null-coalescing double > arrow for the fields which should be omitted if the value is null: > > $array = [ > 'field1' => $param1, > 'field2' => $param2, > 'field3' ?=> $param3, > ]; > > In this case, if $param3 === null, the created array would only > contain 'field1' and 'field2' from start, without the need to later > get rid of 'field3'. > > This syntax will also allow more generalized conditions. For example, > instead of: > > if ($someCondition) { > $array['field'] = $value; > } > > You could create such array from start, if you are OK with such code-style: > > $array = [ > // other fields > 'field' ?=> $someCondition ? $value : null, > ]; > > The token '?=>' given here is mainly just an example, because the > exact form should be discussed anyway (this one, as well as others, > have pros and cons). > > So, before I create an RFC for this feature, I would like to get > initial feedback: would this feature be welcome in general? > > Prototype implementation for it: > https://github.com/Amegatron/php-src/tree/conditional-array-elements > > Or just the diff with current master: > https://github.com/php/php-src/compare/master...Amegatron:php-src:conditional-array-elements > > This is still a prototype though, some additional work must be done of > course, not counting the tests. > > A slightly bigger example: > https://gist.github.com/Amegatron/06da8770e46e116b05f1c290cb0d56fc > > Looking forward to your feedback. > > Cheers, > Alexander Egorov.
My first thought is that the current code, which assigns potentially null values, works fine if you throw an array_filter() at it at the end. $array = [ 'field1' => $param1, 'field2' => $param2, 'field3' => $param3_which_is_null, ]; $a = array_filter($array); // $a now omits the null fields My second thought is that this is yet another reason why using associative arrays as if they were a data structure is wrong and should be avoided; just use a class and everything will be fine. If you need to serialize it later, there's many serializers on the market if JsonSerialize isn't sufficient. So this doesn't seem like a worthwhile addition to me. --Larry Garfield

Alexander Egorov

95 days ago
Thanks for the feedback! пт, 29 мая 2026 г., 19:06 Larry Garfield <larry@garfieldtech.com>:
> My first thought is that the current code, which assigns potentially null values, works fine if you throw an array_filter() at it at the end. > > $array = [ > 'field1' => $param1, > 'field2' => $param2, > 'field3' => $param3_which_is_null, > ]; > > $a = array_filter($array); > // $a now omits the null fields
array_filter will only cover the cases when you need to filter all fields by the same criteria (null's in this case). But it does not fit the case when you still have some mandatory fields even if they are null, but some are optional. At least in the simplest form, but otherwise in more complex forms we'll still come up with additional code.
> My second thought is that this is yet another reason why using associative arrays as if they were a data structure is wrong and should be avoided; just use a class and everything will be fine. If you need to serialize it later, there's many serializers on the market if JsonSerialize isn't sufficient.
Wrong or not, using arrays as an intermediate for serializing is still very common. Also, it is a common case when developers have their in-house serialization mechanisms. But whatever serialization you use, the serialization library by itself will still need to perform corresponding "if"'s or other logic to conditionally include/exclude the fields. So, such feature can prove useful for serialization libraries themselves. Another thing is that we don't only work with production-ready code which presumably already has or should have a proper "infrastructure" for serialization. We can still work with some draft or MVP projects where we need to do things fast and simple first. And such feature can prove handy.

Larry Garfield

95 days ago
On Fri, May 29, 2026, at 11:58 AM, Alexander Egorov wrote:
> array_filter will only cover the cases when you need to filter all > fields by the same criteria (null's in this case). > But it does not fit the case when you still have some mandatory fields > even if they are null, but some are optional. > At least in the simplest form, but otherwise in more complex forms > we'll still come up with additional code.
A data format that has a mix of required-even-if-null and optional fields is a broken data format. We should not design language features around a broken data format. (I realize that the broken data format is often provided by a 3rd party, not the PHP developer, so it's not the PHP developer's fault that the data format is broken. But the point stands that we should not build around that.)
>> My second thought is that this is yet another reason why using associative arrays as if they were a data structure is wrong and should be avoided; just use a class and everything will be fine. If you need to serialize it later, there's many serializers on the market if JsonSerialize isn't sufficient. > > Wrong or not, using arrays as an intermediate for serializing is still > very common. > Also, it is a common case when developers have their in-house > serialization mechanisms. > > But whatever serialization you use, the serialization library by itself will > still need to perform corresponding "if"'s or other logic to > conditionally include/exclude the fields. > So, such feature can prove useful for serialization libraries themselves. > > Another thing is that we don't only work with production-ready code > which presumably already > has or should have a proper "infrastructure" for serialization. We can > still work with some draft > or MVP projects where we need to do things fast and simple first. And > such feature can prove handy.
Disclosure: I am the author of Crell/Serde, one of the aforementioned serialization libraries. It's also super easy to just "drop into" a project and start using, even without wiring it into a container or anything. And I wouldn't make use of this feature, as it doesn't fit the way Serde works to begin with. --Larry Garfield

Alexander Egorov

95 days ago
On Fri, May 29, 2026 at 8:14 PM Larry Garfield <larry@garfieldtech.com> wrote:
> > On Fri, May 29, 2026, at 11:58 AM, Alexander Egorov wrote: > > > array_filter will only cover the cases when you need to filter all > > fields by the same criteria (null's in this case). > > But it does not fit the case when you still have some mandatory fields > > even if they are null, but some are optional. > > At least in the simplest form, but otherwise in more complex forms > > we'll still come up with additional code. > > A data format that has a mix of required-even-if-null and optional fields is a broken data format. We should not design language features around a broken data format. (I realize that the broken data format is often provided by a 3rd party, not the PHP developer, so it's not the PHP developer's fault that the data format is broken. But the point stands that we should not build around that.)
I generally agree with you about broken data formats, but I think it does not really relate to the language feature itself. The reason and motivation why I'm suggesting this feature is not to promote building around broken data formats, but to have a convenient syntax for what is anyway being done more or less often. It is always developer's decision or necessity to do things this or that way, and PHP anyway (as any other language) allows developers to have whatever data-structures they want without obligation to do things "right", because "right" is often very relative. The language is first and foremost an instrument. Specifically, associative arrays by themselves are completely decoupled from what exactly they are used for, and PHP anyway allows to dynamically add or remove (unset) keys from them. So, the feature I'm suggesting is about having a more convenient tool for that, and not about building around bad data formats.

Alex Pierstoval Rock

92 days ago
Le 29/05/2026 à 19:46, Alexander Egorov a écrit :
> On Fri, May 29, 2026 at 8:14 PM Larry Garfield<larry@garfieldtech.com> wrote: >> A data format that has a mix of required-even-if-null and optional fields is a broken data format. We should not design language features around a broken data format. (I realize that the broken data format is often provided by a 3rd party, not the PHP developer, so it's not the PHP developer's fault that the data format is broken. But the point stands that we should not build around that.) > I generally agree with you about broken data formats, but I think it does not > really relate to the language feature itself. The reason and motivation why I'm > suggesting this feature is not to promote building around broken data formats, > but to have a convenient syntax for what is anyway being done more or > less often.
This argument doesn't hold. I've mostly been working on legacy PHP projects for the past 18 years, and almost all of them benefited from PHP's quirkness, sometimes in the ugliest possible way, especially when it involved arrays. I know that "in the past" we didn't have good handling of data structures and validations, but nowadays, nobody should rely on older problematic practices just because the language allows doing so. If an app has broken formats, I think it's hugely counter-productive that the PHP language itself evolves in favor of making broken formats "more readable", because it doesn't at all encourage modernisation of older codebases, or of bad practices whatever their age.
> It is always developer's decision or necessity to do things this or that way, > and PHP anyway (as any other language) allows developers to have whatever > data-structures they want without obligation to do things "right", because > "right" is often very relative. The language is first and foremost an > instrument.
A woodworker willing to cut big panels could use a hand-driven jigsaw, but these days we also have rail-guided circular saws. Just because some people use jigsaws doesn't mean we should improve the whole setup around jigsaws. They can keep it, of course, but more experienced people will definitely remind them that cutting panels with a rail-guided circular saw is faster, more precise, and less damage-prone. Same here. Just because we have arrays doesn't mean they should be recommended as a safe data structure.
> Specifically, associative arrays by themselves are completely > decoupled from what > exactly they are used for, and PHP anyway allows to dynamically add or > remove (unset) > keys from them. So, the feature I'm suggesting is about having a more convenient > tool for that, and not about building around bad data formats.
As said by Larry: the reasons you expose for your RFC are usually considered not-so-good practices. Just because an array allows you to do a lot of silly things doesn't mean you should do it. And if the language evolves with a new favor for such not-so-good practices, only a niche part of people will actually go against it. For instance, I haven't even used property hooks because they often imply having anemic stateful classes with getters and setters, and using property hooks hides all the logic that one could have with rich meaningful self-descriptive mutating methods. But I've seen people overly use property hooks. Same as constructor property promotion: lots of people use them for everything, sometimes mixing constructor-promoted properties and class-declared properties, and it's so annoying to mix both that I usually use constructor promotion only for DI. Not all features are meant to be used "just to be used", neither to please one or two people that want to ease a bad way of coding. After all, nothing prevents you from writing this: ``` $someCondition && $array['field'] = $value; ``` Instead of your initial proposal: ``` if ($someCondition) { $array['field'] = $value; } ``` So why won't we code like this, while it would potentially help making a one-liner out of it for all optional fields?

Alexander Egorov

92 days ago
On Mon, Jun 1, 2026 at 4:05 PM Alex Rock <pierstoval@gmail.com> wrote:
> > Le 29/05/2026 à 19:46, Alexander Egorov a écrit : > > On Fri, May 29, 2026 at 8:14 PM Larry Garfield <larry@garfieldtech.com> wrote: > > A data format that has a mix of required-even-if-null and optional fields is a broken data format. We should not design language features around a broken data format. (I realize that the broken data format is often provided by a 3rd party, not the PHP developer, so it's not the PHP developer's fault that the data format is broken. But the point stands that we should not build around that.) > > I generally agree with you about broken data formats, but I think it does not > really relate to the language feature itself. The reason and motivation why I'm > suggesting this feature is not to promote building around broken data formats, > but to have a convenient syntax for what is anyway being done more or > less often. > > This argument doesn't hold. I've mostly been working on legacy PHP projects for the past 18 years, and almost all of them benefited from PHP's quirkness, sometimes in the ugliest possible way, especially when it involved arrays. > > I know that "in the past" we didn't have good handling of data structures and validations, but nowadays, nobody should rely on older problematic practices just because the language allows doing so.
I may have probably formulated my argument badly, but I didn't mean that "since PHP already allows us to do bad things, let's do it more comfortably". I meant that there is nothing bad in making such "variable" arrays in the first place.
> It is always developer's decision or necessity to do things this or that way, > and PHP anyway (as any other language) allows developers to have whatever > data-structures they want without obligation to do things "right", because > "right" is often very relative. The language is first and foremost an > instrument. > > A woodworker willing to cut big panels could use a hand-driven jigsaw, but these days we also have rail-guided circular saws. Just because some people use jigsaws doesn't mean we should improve the whole setup around jigsaws. They can keep it, of course, but more experienced people will definitely remind them that cutting panels with a rail-guided circular saw is faster, more precise, and less damage-prone. > Same here. > Just because we have arrays doesn't mean they should be recommended as a safe data structure.
Whatever instrument or feature you give to the people, some will always find bad or inappropriate use for them, and you can't control it. Even if the feature by itself is supposed to be the "absolutely best practice in the world". I could give numerous examples when any good feature of the language is used in an unimaginable way, and PHP didn't promote that in any way. The fact that we now have rail-guided circular saws does not mean at all that hand-driven jigsaws are deprecated. They are still thoroughly used and still have their own applications, and switching to the rail-guided saw may not even be possible, because these are two different instruments, each for its own "domain". What you're essentially saying is that people are supposed to only "cut big panels" with PHP, and not do some other kinds of things, and thus people should necessarily switch to circular saws. Which is obviously not the case, because lots of people do other kinds of "woodworking" for which "hand-driven jigsaw" in the context of PHP is still preferable.
> Specifically, associative arrays by themselves are completely > decoupled from what > exactly they are used for, and PHP anyway allows to dynamically add or > remove (unset) > keys from them. So, the feature I'm suggesting is about having a more convenient > tool for that, and not about building around bad data formats. > > As said by Larry: the reasons you expose for your RFC are usually considered not-so-good practices. Just because an array allows you to do a lot of silly things doesn't mean you should do it. > > And if the language evolves with a new favor for such not-so-good practices, only a niche part of people will actually go against it. > > For instance, I haven't even used property hooks because they often imply having anemic stateful classes with getters and setters, and using property hooks hides all the logic that one could have with rich meaningful self-descriptive mutating methods. But I've seen people overly use property hooks. Same as constructor property promotion: lots of people use them for everything, sometimes mixing constructor-promoted properties and class-declared properties, and it's so annoying to mix both that I usually use constructor promotion only for DI. > > Not all features are meant to be used "just to be used", neither to please one or two people that want to ease a bad way of coding.
Exactly. That's what I was talking about above. The fact that some people would find a bad use of some instrument or feature does not mean that this instrument or feature is bad by itself. When you and Larry are talking about "bad practices", as I see it, you're mostly talking about some specific applications of arrays, and what you're concerned about is that in these specific applications "free-form" arrays would be bad. But as I've said, arrays as a language feature are decoupled from that, from exact usages, and there is nothing bad in manipulating them the way you like it. It's like string concatenation. Is it bad by itself? Obviously not. But in some specific applications it can be considered a bad practice.
> If an app has broken formats, I think it's hugely counter-productive that the PHP language itself evolves in favor of making broken formats "more readable", because it doesn't at all encourage modernisation of older codebases, or of bad practices whatever their age.
Again, arrays are not about broken data formats. Arrays are a technical instrument for whatever purposes. They are not just outdated "ancestors" of strict classes or any other fixed data structures. As it seems to me, both you and Larry miss that associative arrays are also (or probably first and foremost) key-value dictionaries. And the fact that some people use them badly to describe some specific objects does not make arrays bad. But using them as key-value dictionaries with a variable set of keys is an absolutely valid application of them. And that's why it is good to have possibilities to manipulate them.
> After all, nothing prevents you from writing this: > > ``` > $someCondition && $array['field'] = $value; > ```
Some people, including myself, consider this exact thing as a bad practice. A logical expression floating in the air, the result of which is not used (neither assigned nor returned). Moreover, an expression for the sole purpose of implicit invocation of some logic. It's just a hack exploiting the way such logical expressions are evaluated. Meanwhile I'm aware that such a construct is frequently used even inside the most popular frameworks and libraries.

Lynn

95 days ago
On Fri, May 29, 2026 at 6:07 PM Larry Garfield <larry@garfieldtech.com> wrote:
> > My first thought is that the current code, which assigns potentially null > values, works fine if you throw an array_filter() at it at the end. > > $array = [ > 'field1' => $param1, > 'field2' => $param2, > 'field3' => $param3_which_is_null, > ]; > > $a = array_filter($array); > // $a now omits the null fields > > My second thought is that this is yet another reason why using associative > arrays as if they were a data structure is wrong and should be avoided; > just use a class and everything will be fine. If you need to serialize it > later, there's many serializers on the market if JsonSerialize isn't > sufficient. > > So this doesn't seem like a worthwhile addition to me. > > --Larry Garfield >
While I do agree, I found myself using arrays because I don't always want to depend on an external library for something as simple as json_encode, nor do I want to create 5 different files for 5 different objects for a nested structure with the current PSR standards. One of my use-cases is an external GQL library where the data is sent as json, and with dozens of queries/mutations that would easily lead to 50~60 extra classes _just_ for serialization purposes. I've found myself writing code like this more frequently: ``` return [ 'key1' => $this->value1, 'key2' => $this->value2, ...($this->value3 ? ['key3' => $this->value3] : []), ]; ``` It's not always json, sometimes it's also DB parameters where binding `null` can mean something different than not having the key. Same for data that ends up converted to XML where an empty element means something different than an absent element. I'm not specifically for or against this change, I just want to note that the presence of a key with null value vs an absent key can make a difference, whether you own the consuming code or not. This particular RFC would add syntactic sugar that I would most certainly use if it was available to me. I also want to note that array_filter is a falsey check by default, and feels like overhead just to remove what you've just added.