php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #79288 Allow string key array unpacking inside arrays with array_merge semantics
Submitted: 2020-02-19 21:48 UTC Modified: 2020-02-19 23:02 UTC
From: caelan89 at gmail dot com Assigned:
Status: Suspended Package: Arrays related
PHP Version: 7.4.2 OS: n/a
Private report: No CVE-ID: None
 [2020-02-19 21:48 UTC] caelan89 at gmail dot com
Description:
------------
A wise person by the handle of "nikic" once said to me: "Pro tip: Don't be a total dick in your bug reports, and you might get a more information reply next time."

He is totally right. Don't be me. Don't go barging in with such an arrogant and demeaning tone. It does a disservice to all parties involved.

See: https://bugs.php.net/bug.php?id=79285&edit=2

Please, if you would accept my apology, I am eager to discuss this feature:

---

You've added array unpacking inside of arrays. However, I feel that it could benefit from an additional feature.

You do not allow this:

$a1 = [
  'test' => 1
];

$a2 = [
  'test-2' => 2
];

$a3 = [
  ...$a1,
  ...$a2
];

From my understanding, it would be semantically equivalent to:

$a3 = array_merge($a1, $a2);

Test script:
---------------
$a1 = [
  'test' => 1
];

$a2 = [
  'test-2' => 2
];

$a3 = [
  ...$a1,
  ...$a2
];


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-02-19 23:02 UTC] requinix@php.net
-Status: Open +Status: Suspended -Package: PHP Language Specification +Package: Arrays related
 [2020-02-19 23:02 UTC] requinix@php.net
I was not polite either. My IRL bad mood leaked onto the internet.

I believe not unpacking keys with function arguments was because of the potential - no, guaranteed - confusion with associative arrays. Without a named arguments feature, PHP can only really do one thing: unpack the array in the order the entries were inserted. The order you'd get with a foreach. That runs directly contrary to how associative arrays (aka hashes or dictionaries) are typically used in programming: where the order doesn't matter in the slightest. Unpacking an associative array into function arguments just does not make sense right now.

But that doesn't apply to unpacking arrays *into arrays*. However, what could be a problem is the potential for one unpacked array to overwrite the keys of a previous unpacked array.

Regardless of all of the above, this sort of change needs some discussion in a place that's better suited than this bug tracker, ie. the mailing list. Possibly an RFC, depending how it goes.
 [2020-02-20 09:50 UTC] caelan89 at gmail dot com
@requinx, you'd be entirely justified in it (maybe not to the extent of an eye for an eye), but I did basically come in and shit all over work volunteered by good people.

I'll bring one of my comments (redacted the bad parts) from the old issue thread, as it is still pertinent.

I agree discussion would be necessary to map out all advantages and disadvantages - I wouldn't know where to start submitting an RFC. I don't know C++, so I could not contribute to PHP in that way anyway. Though I strongly feel this would be a very useful feature.


--- from previous issue ---

Are there any downsides to allowing string keys when unpacking inside arrays?

I agree that allowing string keys for function arguments doesn't seem to semantically quite fit together. Indexes don't map to arbitrary strings.

But why not for spreading within an array?

You could then simultaneously define default values, user customisable values and fixed values all within the array syntax.

For example:

$custom = [
  'value' => true,
];

$values = [
  'value' => false,
  ...$custom
  'fixed-value' => $whatever
];

Indexed arrays would concatenate, like with array_merge.

String keys will overwrite, like with array_merge.

I feel it makes more sense for the semantics to match array_merge.

--- end comment ---


> "However, what could be a problem is the potential for one unpacked array to overwrite the keys of a previous unpacked array."

I think that would be the point of unpacking inside the array.

I think people tend to conceptualise associative arrays as being different from indexed arrays. They are used for different purposes. So, I think it makes sense that their behaviour would differ when used in certain conditions.

PHP already treats arrays differently in certain cases, like when passed to array_merge. The RFC even proposes the array unpacking inside arrays as a replacement for array_merge when simply concatenating index arrays.

Nobody really explicitly defines indexes in an array, they leave that to the interpreter, unless they're using generated code or something, but PHP doesn't seem to care if you explicitly define indexes, so long as they increment from zero.

I think people use associative arrays in PHP like objects are used in JavaScript, for the most part. The order of properties was never guaranteed when iterating them in JS. But that didn't really cause all that many problems, though order of properties is now guaranteed in newer interpreters to be in the order in which they were assigned.

But, one order which will always be guaranteed, is the order in which string keys are defined, due to the code itself being linear. So, order underlying isn't an issue, even though PHP does indeed maintain order during iteration.

PHP/JS is one of the most common pairings. By necessity, given, but, nonetheless paired via the web.

I feel it makes sense for string keys to overwrite. It's what you'd intuitively expect to happen in the above example.

It has a lot of uses. I can't help but find this just icky:

$custom = [
  'value' => true
];

$values = array_merge([
  'value' => false
], $custom, [
  'fixed-value' => $whatever
]);


I was actually in converting an example like the above to the new unpacking syntax that I discovered string keys are currently not allowed.
 [2020-02-24 15:29 UTC] caelan89 at gmail dot com
I never knew PHP supported this - this kind of renders any real necessity outside of "might as well do it anyway" quite moot.

$a1 = [
    'one' => 'foo'
];

$a2 = [
    'one' => 'bar',
    'two' => 2
];

$a3 = $a1 + $a2;

var_dump($a3);

// Yields:
//
// array(2) {
//    ["one"]=>
//    string(3) "foo"
//    ["two"]=>
//    int(2)
// }
 [2020-02-24 15:30 UTC] caelan89 at gmail dot com
Saying that, it's not as neat when used for the purpose I describe in an earlier comment.
 [2020-02-24 15:32 UTC] caelan89 at gmail dot com
No, wait, I'm being a massive tool.

It doesn't overwrite string keys, it will only add attributes which don't already exist in the left operand.
 [2020-02-25 13:33 UTC] rowan dot collins at gmail dot com
If you haven't already, it's worth looking through the discussion of the original RFC, where string key unpacking was originally included, but dropped to get the core feature in: https://externals.io/message/103452 https://externals.io/message/105072 https://externals.io/message/103458

I believe the main reason it was dropped was not because there wasn't support for the concept in general, but because it wasn't clear exactly how it should behave. As you've discovered, we already have array_merge and the + operator with different behaviour; it's unclear if the ... operator should mimic one of those, or be yet a third variation of the same thing.

As requinix touched on, it was also deemed important for unpacking within arrays to match unpacking in argument lists. If named arguments are added in future, then we might have a stronger reason for picking a particular behaviour for this scenario; conversely, if we pick a behaviour now, we might regret it when adding named arguments.
 [2020-02-25 14:45 UTC] caelan89 at gmail dot com
@rowan,

Those are some excellent points. I understand the reasoning for the omission.

Thank you. I shall eagerly await named arguments - that sounds like a useful feature,
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Oct 31 23:01:28 2024 UTC