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