Hey all,
I've been bouncing this idea of fixing all comparison operations in one
fell swoop, although with an opt-in declare in the spirit of strict_types.
Here's the gist: ==, < and > plus all the comparisons done inside switch
statements and arrays are not very safe. === helps some, but does nothing
for switches and < >.
My idea is to add a strict_comparisons declaration that you can add at the
beginning of a file in the same way as strict_types. The effect would be
that all normal comparisons would make a type check before doing the actual
comparison, and throw a TypeError exception if the types don't match.
In other words:
<?php declare(strict_comparisons=1);
$two = "2";
if ($two > 1) {
echo "This sorta works without strict_comparisons=1" . PHP_EOL;
}
...would throw a TypeError exception after this change.
This change would mostly go into zend_operators.c compare_function. So it
would affect every comparison operation, including switch statements and
things like in_array.
I've implemented a prototype with a couple of test cases in
https://github.com/paytrail/php-src/tree/experimental/strict_comparisons
Please take a look and let me know if this would be worth a more official
RFC.
https://github.com/paytrail/php-src
--vk
Hi Vesa,
My idea is to add a strict_comparisons declaration that you can add at the
beginning of a file in the same way as strict_types.Please take a look and let me know if this would be worth a more official
RFC.
I think it deserves an RFC.
One thing that might make people hesitant about this, is that it's
likely that you would want to have the occasional weak comparison in a
file.
However that should mostly covered by just adding a cast where needed
presumably? e.g. like:
$foo = '5 apples';
if ((int)$foo == 5) {
echo "eh, close enough";
}
cheers
Dan
Hi Vesa,
On 19 September 2016 at 14:04, Vesa Kaihlavirta vpkaihla@gmail.com
wrote:My idea is to add a strict_comparisons declaration that you can add at
the
beginning of a file in the same way as strict_types.Please take a look and let me know if this would be worth a more official
RFC.I think it deserves an RFC.
Cool! I'll write some more unit test cases and start working on the RFC
text.
One thing that might make people hesitant about this, is that it's
likely that you would want to have the occasional weak comparison in a
file.
However that should mostly covered by just adding a cast where needed
presumably? e.g. like:$foo = '5 apples';
if ((int)$foo == 5) {
echo "eh, close enough";
}
Yeah, that works. I added that as a test case.
What still worries me personally is ===. What do you think would be the
least incorrect way to handle === (and other identicality operations) when
strict_comparisons is in effect? I thought of the following options:
-
=== works like ==, that is, makes type checks and throws exceptions if
the types don't match -
=== is not affected by strict_comparisons. It would then be weaker
than == when s_c is on (since it would just return false instead of
throwing). That would offer a sort of a convenient way out of the strictest
comparison mode, but might be confusing. -
=== is disabled/not allowed when s_c is on. Would lessen the risk of
confusion.
Thoughts?
--vk
cheers
Dan
Am 21.09.16 um 14:49 schrieb Vesa Kaihlavirta:
Hi Vesa,
On 19 September 2016 at 14:04, Vesa Kaihlavirta vpkaihla@gmail.com
wrote:My idea is to add a strict_comparisons declaration that you can add at
the
beginning of a file in the same way as strict_types.Please take a look and let me know if this would be worth a more official
RFC.
I think it deserves an RFC.
+1 for RFC
Cool! I'll write some more unit test cases and start working on the RFC
text.One thing that might make people hesitant about this, is that it's
likely that you would want to have the occasional weak comparison in a
file.However that should mostly covered by just adding a cast where needed
presumably? e.g. like:$foo = '5 apples';
if ((int)$foo == 5) {
echo "eh, close enough";
}Yeah, that works. I added that as a test case.
What still worries me personally is ===. What do you think would be the
least incorrect way to handle === (and other identicality operations) when
strict_comparisons is in effect? I thought of the following options:
=== works like ==, that is, makes type checks and throws exceptions if
the types don't match=== is not affected by strict_comparisons. It would then be weaker
than == when s_c is on (since it would just return false instead of
throwing). That would offer a sort of a convenient way out of the strictest
comparison mode, but might be confusing.=== is disabled/not allowed when s_c is on. Would lessen the risk of
confusion.Thoughts?
--vk
I'd prefer (2). At least in our code base (~3M LOC) it's the uptrending
comparison, and widely used for type and range checking, imidiately
followed by proper handling of the error cases.
IMHO anything other than (2) would be too big of a BC break to get votes.
Best,
Thomas
What still worries me personally is ===. What do you think would be the
least incorrect way to handle ===
- === is not affected by strict_comparisons.
I think not changing it is the correct thing to do.....but I think it
needs more thinking about.
Btw, the RFC would need to cover all cases of comparison. e.g. within
for loops as well as if statements because:
$initialValue = "2bananas";
for ($x=$initialValue ; $x<10; $x++) {
echo "$x\n";
}
cheers
Dan
My idea is to add a strict_comparisons declaration that you can add at
the
beginning of a file in the same way as strict_types. The effect would
be
that all normal comparisons would make a type check before doing the
actual
comparison, and throw a TypeError exception if the types don't match.
Hm, that's definitely an interesting idea. It occurs to me that there are a few things to "being strict" beyond type equality.
For instance === will also (I think) stop PHP juggling both sides of a comparison, e.g. two numeric strings will sometimes be compared numerically rather than bytewise.
Using if statements with non-booleans also feels closely related - should the setting (or another new flag?) throw an error on if($foo) being implicitly processed as if(empty($foo))?
Regards,
--
Rowan Collins
[IMSoP]
Am 19.09.2016 um 15:04 schrieb Vesa Kaihlavirta vpkaihla@gmail.com:
<?php declare(strict_comparisons=1);
$two = "2";
if ($two > 1) {
echo "This sorta works without strict_comparisons=1" . PHP_EOL;
}...would throw a TypeError exception after this change.
This sounds like a bad idea to me: Changing the language semantics of something so basic as the comparison operators seems like asking for trouble. One programmer will try to incorporate code from non-strict parts into strict parts and possibly gets exceptions even though the code works. Another programmer is puzzled about all the type casts (or even try/catch constructs) when moving code the other way around.
On top of that: Making it a runtime-setting or file-wide declaration seems like the most troublesome option.
Reminds me way too much of magic quotes :-)
Let's take a step back: If you want type-safety and your program is more or less well-structured then type declarations on function parameters should IMHO be more than sufficient.
Regards,
- Chris
I find the idea of making ‘==‘ which has always been a loose comparison, have a new optional way to be ‘more strict’ than ‘===‘ to be quite odd.
I would however love a way to have strict comparisons in a switch statement.
Cheers
Stephen
Am 19.09.2016 um 15:04 schrieb Vesa Kaihlavirta vpkaihla@gmail.com:
<?php declare(strict_comparisons=1);
$two = "2";
if ($two > 1) {
echo "This sorta works without strict_comparisons=1" . PHP_EOL;
}...would throw a TypeError exception after this change.
This sounds like a bad idea to me: Changing the language semantics of something so basic as the comparison operators seems like asking for trouble. One programmer will try to incorporate code from non-strict parts into strict parts and possibly gets exceptions even though the code works. Another programmer is puzzled about all the type casts (or even try/catch constructs) when moving code the other way around.
On top of that: Making it a runtime-setting or file-wide declaration seems like the most troublesome option.
Reminds me way too much of magic quotes :-)Let's take a step back: If you want type-safety and your program is more or less well-structured then type declarations on function parameters should IMHO be more than sufficient.
Regards,
- Chris
I would however love a way to have strict comparisons in a switch statement.
I've been pondering an idea for ages of a generalised syntax for switch
to specify an operator to use, so you'd do something like this:
switch ( $foo ) use ( === ) {
case 1:
something();
break;
case '1':
not_the_same_thing();
break;
}
At some point, I'll get round to attempting a proof of concept and
writing up an RFC...
Regards,
Rowan Collins
[IMSoP]
I've been pondering an idea for ages of a generalised syntax for switch to
specify an operator to use, so you'd do something like this:
That's technically possible already:
function foobar($foo)
{
switch (true) {
case $foo === '1':
echo "close but no cigar\n";
break;
case $foo === 1:
echo "identical\n";
break;
case $foo == 1:
echo "why you do this\n";
break;
}
}
foobar(1);
foobar("1 apple");
It's just a little bit icky.
cheers
Dan
On 23 September 2016 at 17:40, Rowan Collins rowan.collins@gmail.com
wrote:I've been pondering an idea for ages of a generalised syntax for
switch to
specify an operator to use, so you'd do something like this:That's technically possible already:
function foobar($foo)
{
switch (true) {
case $foo === '1':
Yeah, switch(true) has always felt like an ugly hack to me. If I ever do write up my idea I'll cover this in the RFC, but the main problem is that you have to repeat the "$foo ===" part in every case, which means a reader can't assume all the cases are of the same form, and in many situations you're better off just using elseifs.
A switch(true) makes more sense if you have a bunch of basically unrelated conditions with the same outcome, at which point a bunch of case labels is possibly easier to maintain than a big chain of boolean ors.
Regards,
--
Rowan Collins
[IMSoP]
Hey all,
I've been bouncing this idea of fixing all comparison operations in one
fell swoop, although with an opt-in declare in the spirit of strict_types.So, I thought about this for a while, and decided against doing this RFC
myself. If anyone else wants to pick it up, go ahead.
Best of luck to you all!
--vk