A PHP syntax for discardable assignments
Recently, John Bafford revived a years-long conversation on expanding the syntax of the PHP foreach statement to include iterating solely over keys. Bafford, who wrote a patch and request for comments (RFC) on the matter back in 2016, hopes to update his work and convince the community to adopt the abbreviated syntax in PHP 8.1. The community took Bafford's general idea and expanded it into other areas of the language.
The PHP foreach statement is designed to iterate over arrays and objects that implement the Traversable interface. PHP arrays are analogous to Python dictionaries. Two varieties of syntax are currently available to foreach: the first extracts the value of each item, while the second extracts both the key and the value:
    $traversable = [
        'A' => 1,
        'B' => 2
    ];
    foreach($traversable as $value) { /* ... */ }
    foreach($traversable as $key => $value) { /* ... */ }
The purpose of Bafford's proposal is to provide an efficient way for the foreach statement to extract only the keys while ignoring the values; he decided on using the void keyword to indicate that the value portion should be discarded:
    foreach($traversable as $key => void) { /* ... */ }
  It's not the first time this idea has been suggested; Chris London had a similar proposal back in
  2013. At the time, London's suggestion didn't gain much traction, and
  contributor Nikita Popov characterized the use case for
  the syntax as "not particularly common.
" Moreover, as Popov
  wrote, PHP already provides multiple different ways of addressing this need
  without adding syntax to the language. One solution is to provide a variable
  for the value in foreach statements and not use it when only the
  keys are needed:
    foreach($array as $key => $_) { /* ... */ }
Note that, in the above, $_ is just a variable to PHP without any special meaning; developers, by convention, sometimes use it to signify an "unused" value. Another alternative that was suggested by Popov is to use the array_keys() function to similar effect. Using this approach, a second, integer-indexed array is created from the original array that contains the keys to iterate over, eliminating the need for an unused variable:
    foreach(array_keys($array) as $key) { /* ... */ }
  The arguments against the new syntax have not changed significantly from
  seven years ago; Popov effectively 
  repeated them in response to Bafford's proposal. In his opinion, it added
  unnecessary complexity to the language, would make foreach
  "marginally slower,
" and there are multiple valid alternatives
  already available to address the problem the RFC looks to solve. Not everyone
  in the community felt that Popov's alternatives were ideal, however. Dik
  Takken 
  noted that the first option creates an unused variable, adding that
  "code inspection currently complains about that, and for good reason,
  which is annoying.
" As for using array_keys(), Markus Fischer
  
  wrote that this solution isn't ideal, either; the array_keys()
  function needs to create a new array, which could be a performance issue.
Some felt that Bafford's choice to use void wasn't the best option. Olle Härstedt suggested that the underscore character might be a better alternative to void:
foreach($iterable as $key => _) { ... }
As justification, Härstedt noted that OCaml uses the underscore symbol when the value of an assignment can be discarded. Unfortunately, _() is also an alias to the gettext() function, making it a poor choice for this purpose. Several participants in the thread preferred the keyword null to void, although Bafford was opposed to that suggestion. He argued that, because null is a value in PHP whereas void is a type, void is the better choice. With the RFC still under discussion, what keyword might ultimately be used is undecided.
Disagreements on the specific keyword aside, Takken suggested that the scope of Bafford's proposal was too narrow, writing:
Perhaps it is a good idea to generalize the RFC to the general concept of "using void to intentionally ignore a variable". Maybe pick just one use case for actual implementation and extend later using followup RFCs.
There are at least two areas where this syntax would be beneficial to the language. The first is captured in Bafford's RFC, and the second is when assigning variables from an array as shown in the example below:
    [, , $a] = ['val1', 'val2', 'val3'];
  To many programmers, the code above might look more like a syntax error than
  a valid expression. It is, however, valid PHP code, which assigns "val3" to
  $a; the seemingly out-of-place commas in the example above indicate
  that $a should be assigned the third value in the source. Härstedt
  
  noted that "anything would be better
" than the current
  comma-only syntax; generalizing Bafford's proposal to include this aspect of
  PHP certainly clarifies what is happening in such an assignment operation:
    [void, void, $a] = ['val1', 'val2', 'val3'];
  Takken's suggestion to generalize the syntax was positively received by
  Härstedt and others, including PHP 8.0 release manager Sara Golemon, who
  
  described both the proposed changes to foreach and the suggested
  improvements to array-value assignments "great, expressive
  syntaxes.
"
  Bafford believes his proposal shouldn't hurt performance. In fact, while he
  was clear that "any performance benefits are secondary
" to the
  syntactical benefits, he did make a case arguing that his proposal would
  benefit the run-time performance of foreach:
In theory, this should be a general performance win any time one needs to iterate over only the keys of an iterable, because it does not require the use of an O(n) iteration and building of the array that array_keys() would, plus it works on non-array types (such as generators or iterators). It also is more performant than foreach($iterable as $key => $_) {}, because it omits the opcode that instructs the engine to retrieve the value.
While Bafford may be correct that there is a theoretical performance gain, he offered no benchmarks to demonstrate that and it is unlikely to be of much practical value. Longtime project member Stanislav Malyshev explained what he felt was faulty in Bafford's analysis. In Malyshev's opinion, eliminating an opcode to retrieve the value wouldn't move the performance needle in a meaningful way:
My opinion has been and remains, absent new data, that if your code performance hinges on a couple of simple opcodes being there, maybe you'd better implement that part in C, but in most real-life applications it is not and any performance gain you might get from such syntax is microscopic.
  As things stand now, Bafford's RFC needs to be updated to capture the
  substance of the thread and address any outstanding issues raised in it. One
  of the key issues is whether Bafford will broaden his RFC to a more
  generalized syntax, or whether he will keep it limited to his original scope.
  The wider scope appears to have fairly broad support in the community, so it
  seems likely the RFC will be updated to reflect that. In an email linked
  above, Bafford summed up where things stand; he also let the community know
  he would be taking a break from computers "for a few weeks.
"
  Since this is all planned for PHP 8.1, there isn't any rush; PHP 8.0 isn't
  scheduled to be released until November 26.
      Posted Oct 14, 2020 20:13 UTC (Wed)
                               by jkingweb (subscriber, #113039)
                              [Link] (2 responses)
       
     
    
      Posted Oct 14, 2020 22:00 UTC (Wed)
                               by coogle (guest, #138507)
                              [Link] (1 responses)
       
     
    
      Posted Oct 14, 2020 22:39 UTC (Wed)
                               by jkingweb (subscriber, #113039)
                              [Link] 
       
     
      Posted Oct 15, 2020 2:44 UTC (Thu)
                               by flewellyn (subscriber, #5047)
                              [Link] (5 responses)
       
> foreach(array_keys($array) as $key) { /* ... */ } 
It works fine, although a shorthand might be nice.  The "$_" syntax might work fine. 
This, however? 
>   [, , $a] = ['val1', 'val2', 'val3']; 
I have absolutely no idea why anyone would want to do that.  Ever.  I look at that construct and the reason for it escapes me completely.  Its existence defies any logic with which I am familiar. 
     
    
      Posted Oct 15, 2020 3:10 UTC (Thu)
                               by dtlin (subscriber, #36537)
                              [Link] (1 responses)
       In destructuring, there should be a way to ignore some values. Python uses  In PHP's case… I guess they don't really have an existing language feature to follow, so anything goes. 
     
    
      Posted Oct 19, 2020 12:44 UTC (Mon)
                               by sytoka (guest, #38525)
                              [Link] 
       
     
      Posted Oct 15, 2020 8:35 UTC (Thu)
                               by Rigrig (subscriber, #105346)
                              [Link] 
       
     
      Posted Oct 15, 2020 8:42 UTC (Thu)
                               by Karellen (subscriber, #67644)
                              [Link] (1 responses)
       I imagine that in an imagined real-world use, ['val1', 'val2', 'val3'] is not a literal, but the result of another expression or a function call, and [,,$a] doesn't just want the third element, but perhaps the 3rd, 4th and 5th. So an actual use might look more like But for example code, the left-hand-side is reduced to a minimal case, and a literal is used for the right-hand-side for clarity. 
     
    
      Posted Oct 15, 2020 21:23 UTC (Thu)
                               by flewellyn (subscriber, #5047)
                              [Link] 
       
     
      Posted Oct 24, 2020 12:28 UTC (Sat)
                               by HelloWorld (guest, #56129)
                              [Link] 
       
     
    A PHP syntax for discardable assignments
      
      If you mean this, yes it does:
A PHP syntax for discardable assignments
      
list(,,$a) = [1, 2, 3];
      
          A PHP syntax for discardable assignments
      
A PHP syntax for discardable assignments
      
A PHP syntax for discardable assignments
      
// Javascript
[,, a] = ['val1', 'val2', 'val3'];
# Python
_, _, a = ['val1', 'val2', 'val3']
# Perl
(undef, undef, $a) = ('val1', 'val2', 'val3');
_ by convention, Perl uses undef, but Javascript already allowed missing items in arrays since the beginning,
a = ['hello',, 'world'];
a[0]; // 'hello'
a[1]; // undefined
a[2]; // 'world'
so allowing it in destructuring is consistent.A PHP syntax for discardable assignments
      
      The first use that comes to mind is regular expression subpatterns:
A PHP syntax for discardable assignments
      
preg_match('/(foo)(bar)(baz)/', 'foobarbaz', $matches);
[, $foo, $bar, $baz] = $matches; // $matches[0] = 'foobarbaz'
      
          A PHP syntax for discardable assignments
      [,,$a, $b, $c] = getChoices();
A PHP syntax for discardable assignments
      
      Given that
The solution is obvious
      
[, , $a] = ['val1', 'val2', 'val3'];
is already valid PHP syntax, the obvious way to do it is
foreach($traversable as $key => ) {
  /* ... *
}
      
          
 
           