I'd like to discuss the addition of the new directive `strict_operators`, which 
can be used to disable type juggling when using operators.
---

MOTIVATION

A substantial part of the PHP dev community, including myself, have a strong 
dislike of type juggling. It's a common source of issues, while the benefits 
over explicit type casting are minimal.

The loose comparison equal (`==`) operator and not equal (`!=`) are a well 
known causes of security issues. While to use of these two operators are 
discouraged, the issues aren't limited to them but also present in all other 
comparison operators as well as arithmetic operators.

Type juggling can be a source of frustration, as it may lead to unexpected 
results. An example;

Universal rules of logic state that if `a > b` and `b > c` then `a > c`

<?php
$a = '42';
$b = 10;
$c = '9 dwarfs';

var_export($a > $b); // true
var_export($b > $c); // true
var_export($a > $c); // false ??
---

PROPOSAL

The `strict_operators` directive would work similar to `strict_types`. If 
`strict_operators=1` is declared, operators will throw a `TypeError` when an 
operator is used with incompatible types.

<?php
declare(strict_operators=1);

$b = 10;

$c = '9 dwarfs';

var_export($b > $c); // TypeError "Type mismatch for greater than ('>') 
operator with integer and string"

Including the equals operator;

<?php
declare(strict_operators=1);

$q = 42;
$r = '42';
$s = '42 dwarfs';

var_export($q == $r); // TypeError "Type mismatch for equals ('==') operator 
with integer and string"

var_export($q == $s); // TypeError "Type mismatch for equals ('==') operator 
with integer and string"

var_export($r == $s); // false

var_export($q === $r); // false

var_export($q == (int)$r); // true

You'd still use `===` to compare values of different types.

The rule also applies to arithmetic operators;

<?php
declare(strict_operators=1);

$b = 10;

$c = '9 dwarfs';

var_export($b + $c); // TypeError "Type mismatch for addition ('+') operator 
with integer and string"

var_export($b + (int)$c); // 19

Using operator on a type that doesn't support it, would also throw a 
`TypeError`, rather than trigger a notice.

<?php
declare(strict_operators=1);

$s = "foo";
$arr = [];

$b = $s . $arr; // TypeError "Unsupported type for concatenation ('.') 
operator, unexpected array"

Last, it would disable type conversion for numeric strings.

<?php
declare(strict_operators=1);

$a = "2.7e1";
$b = "27";

var_dump($a == $b); // false

var_dump((int)$a == (int)$b); // true
---

SCOPE

The directive should only apply to operators and not have other side effects.

For instance; Type casting can still cause similar issues to type juggling, 
especially when casting a string to an integer. In other languages like Python, 
casting "42 dwarfs" to an int throws a `ValueError`. However, this and similar 
issues are outside the scope of this proposal.
---

I believe the directive `strict_operators` fits in the direction PHP is going 
with better support for typing, while not affecting backwards compatibility.

Regards,
Arnold Daniels

[Arnold Daniels - Contact Using 
Spike](https://www.spikenow.com/?ref=spike-organic-signature&_ts=prm5vi)

Reply via email to