Hi All,
Before creating an RFC I wanted to get reactions to the idea of adding FALLTHROUGH option to SWITCH/CASE for when the developer explicitly want logic to fall through to the next case and does not want to use a BREAK.
My simples motivation for this feature is that my IDE (PhpStorm) always flags CASE statements w/o BREAKs because it cannot know when I intend for the logic to fallthrough and not break. If there was an optional FALLTHROUGH then my IDE could flag any CASE statements that do not have a FALLTHROUGH or BREAK — which would indicate an error of my intent — and avoid flagging all the situations where I intentionally want it to fall through.
Beyond that, this might also be useful for other static analysis tools such as PhpStan.
Ust
Additionally it could be added in 8.0 and then in 8.1 flagged with a warning when a CASE does not have one for the two, but only if people don't object to this. While I know some on this list feel strongly that warnings must come with to future plans to generate errors I would personally be 100% okay if it indefinitely generated only a warning.
In summary I want a mechanism to be allow me to explicitly indicate my intent with respect to SELECT/CASE statements. What do you think? Is this worthy of an RFC, or is there some reason a majority would object to such an addition?
Thanks in advance.
-Mike
Additionally it could be added in 8.0 and then in 8.1 flagged with a warning when a CASE does not have one for the two, but only if people don't object to this. While I know some on this list feel strongly that warnings must come with to future plans to generate errors I would personally be 100% okay if it indefinitely generated only a warning.
Would you put this at switch level, or case level?
Unless your plan is to redefine how switch works by default, which would
be quite ambitious, I'm not sure it makes a great deal of sense to add a
token that would effectively no-op in all circumstances.
It sounds like a job for a static analysis comment:
/** @DisableSwitchStatementFallthroughWarning */
switch ($x) {
case 1:
$x = doSomething();
case 2:
doLaLaLaLa();
break;
default:
doTralala();
}
--
Mark Randall
Before creating an RFC I wanted to get reactions to the idea of adding
FALLTHROUGH option to SWITCH/CASE for when the developer explicitly want
logic to fall through to the next case and does not want to use a BREAK.My simples motivation for this feature is that my IDE (PhpStorm) always
flags CASE statements w/o BREAKs because it cannot know when I intend for
the logic to fallthrough and not break. If there was an optional
FALLTHROUGH then my IDE could flag any CASE statements that do not have a
FALLTHROUGH or BREAK — which would indicate an error of my intent — and
avoid flagging all the situations where I intentionally want it to fall
through.Beyond that, this might also be useful for other static analysis tools
such as PhpStan.
Ust
Additionally it could be added in 8.0 and then in 8.1 flagged with a
warning when a CASE does not have one for the two, but only if people don't
object to this. While I know some on this list feel strongly that warnings
must come with to future plans to generate errors I would personally be
100% okay if it indefinitely generated only a warning.In summary I want a mechanism to be allow me to explicitly indicate my
intent with respect to SELECT/CASE statements. What do you think? Is this
worthy of an RFC, or is there some reason a majority would object to such
an addition?
+1. It's 100% opt-in. People can keep using implicit fall-through, their
own /* fallthrough / comments, or the new token. There's virtually no
overhead in the compile phase and it doesn't mess with the jump table
optimizations. There's precedent for this desire in PHP static analyzers
1 as well as other major projects: eg, the Linux Foundation just
completed a 2 year project to remove implicit fall-through in the Linux
kernel 2 ().
That said, some questions:
Do you envision this token accepting an optional argument, as break does,
to fall-through multiple nesting levels? Eg:
<?php
$x = $y = $z = 1;
switch ($x) {
case 1:
switch ($y) {
case 1:
switch ($z) {
case 1: fallthrough 3;
case 2: echo 'z2';
}
}
break;
case 2: echo 'x2'; break;
}
?>
What do you envision the result of indicating fall-through to no subsequent
case? Eg:
<?php
switch ($x) {
case 1: fallthrough;
}
?>
Would a "pragma" (of sorts) be a part of the concept?
<?php declare(strict_break=1);
switch ($x) {
case 1: echo 'x1'; // ImplicitBreakError thrown here
case 2: echo 'x2';
}
?>
(*) Fun trivia: PHP is mentioned in that LWN article about naming
conventions.
Hi Bishop,
I'm not the proposer, but would like to answer your questions anyway.
Do you envision this token accepting an optional argument, as break does,
to fall-through multiple nesting levels? Eg:<?php
$x = $y = $z = 1;
switch ($x) {
case 1:
switch ($y) {
case 1:
switch ($z) {
case 1: fallthrough 3;
case 2: echo 'z2';
}
}
break;
case 2: echo 'x2'; break;
}
?>
I think we should keep it simple - we can always add more features later if
a real need reveals itself.
I note that the Go version linked to explicitly forbids the use of
"fallthrough" in a conditional, and a multi-level fallthrough is
effectively the same thing: the control flow in your example is something
like if ( $y==1 && $z == 1 ) { fallthrough; } else { break; } I would have
thought that by the time you've got nested switch statements with
conditional fallthrough on multiple levels, the code is going to be very
hard to reason about, so unless there's a key use case, I'd leave the
complexity out of the language.
There might be use cases for single-level conditional fallthrough, but I'd
lean towards defining it as Go has: as a marker at the end of the case
block only. By far the most common use of it I've seen is like Mike's:
case x:
additional pre-processing
fallthrough
case y:
shared processing
break
What do you envision the result of indicating fall-through to no subsequent
case? Eg:<?php
switch ($x) {
case 1: fallthrough;
}
I think it would be perfectly fine for this to do nothing. Currently you
can write both
switch ($x) {
case 1:
}
and
switch ($x) {
case 1: break;
}
In general, I really like this idea; I've always wished switch worked this
way.
Regards,
Rowan Tommins
[IMSoP]
+1. It's 100% opt-in. People can keep using implicit fall-through, their own /* fallthrough / comments, or the new token. There's virtually no overhead in the compile phase and it doesn't mess with the jump table optimizations. There's precedent for this desire in PHP static analyzers [1] as well as other major projects: eg, the Linux Foundation just completed a 2 year project to remove implicit fall-through in the Linux kernel [2] ().
That said, some questions:
Hi Bishop,
Thank you for the questions.
Do you envision this token accepting an optional argument, as break does, to fall-through multiple nesting levels? Eg:
No. I had not envisioned anything more than a single statement that would indicate to PHP and other tools that a developer intends to not use a break.
What you suggest had not occurred to me, and is an interesting idea. But I think I would prefer — like Rowan Tommins argued — that we should keep it simple.
Being able to fallthrough many levels would be an extra feature we can already accomplish in other, more explicit ways. I would rather focus on targeting a use-case we cannot currently address, i.e. for PHP itself and other tools to be able to flag lack of an explicit case exiting action.
What do you envision the result of indicating fall-through to no subsequent case? Eg:
<?php
switch ($x) {
case 1: fallthrough;
}
?>
Since it would have no effect that could be flagged or not flagged as a warning.
It might be nice to allow it so that refactoring is less likely to result in a warning.
Would a "pragma" (of sorts) be a part of the concept?
<?php declare(strict_break=1);
switch ($x) {
case 1: echo 'x1'; // ImplicitBreakError thrown here
case 2: echo 'x2';
}
?>
Yes, but recent discussions on this list lamented the concern that we could end up with tens if not hundreds of pragmas, and I concur that would be no fun.
So how we would indicate is an open question PHP should answer before adding a pragma for fallthrough. As an aside, I would be excited to see that discussion start in earnest.
Also, I am sure you remember that Nikita proposed an idea loosely described as "Editions" and that might be the way to go. Imagine the following:
<?php declare(edition=2020);
switch ($x) {
case 1: echo 'x1'; // ImplicitBreakError thrown here
case 2: echo 'x2';
}
Or another approach could just be version specific:
<?php declare(strict[version]=php8);
switch ($x) {
case 1: echo 'x1'; // ImplicitBreakError thrown here
case 2: echo 'x2';
}
For these though, the devil would be in the details.
-Mike