Hi,
currently when using array destructuring the variables are assigned as
they are. For example we split a string with explode all variables will
contain strings:
$data = "foo:*:1023:1000::/home/foo:/bin/sh";
[$user, $pass, $uid, $gid, $gecos, $home, $shell] = explode(":", $data);
If we want to write functions consuming $uid and $gid as integer values
with strict types enabled we need to cast the values afterwards:
$uid = (int) $uid;
$gid = (int) $gid;
// or during the function call
$myConsumingObject->myConsumingFunction((int) $uid, (int) $gid);
I think you get my point. How about adding some syntactic sugar and
allow type casting inside the detructuring expression?
$data = "foo:*:1023:1000::/home/foo:/bin/sh";
[$user, $pass, (int) $uid, (int) $gid, $gecos, $home, $shell] =
explode(":", $data);
// $uid and $gid are integer values now. All other variables remain as
they are and contain strings
An example with associative arrays in loops:
$array = [
[
'name' => 'a',
'id' => '1'
],
[
'name' => 'b',
'id' => '2'
],
];
foreach ($array as ['id' => (int) $id, 'name' => $name]) {
// $id contains integer values
}
Further thoughts: when using the list() reference assignment implemented
in PHP7.3 the referenced value could be casted (something to discuss
about, maybe as future scope as casting a reference assignment currently
isn't supported):
$array = [1, 2];
[(string) $a, (string) &$b] = $array;
// $a would be a string: '1'
// $b would be a string: '2'
// $array would contain one integer and one string element: [1, '2']
Thoughts?
How about adding some syntactic sugar and
allow type casting inside the detructuring expression?$data = "foo:*:1023:1000::/home/foo:/bin/sh";
[$user, $pass, (int) $uid, (int) $gid, $gecos, $home, $shell] =
explode(":", $data);
On the one hand, this seems fairly straightforward, and although casts wouldn't normally appear on the left side of an expression, the intent is pretty clear.
On the other hand, this is exactly the kind of thing where strict_types=1 makes things worse - you'll actually get better error output if you use strict_types=0 and pass the string to a function marked as requiring int. By forcing a cast, you're actually silencing the error, and turning all unrecognised values to 0.
If the desire is for stricter type handling, we probably need stricter casts, perhaps using different syntax like (int!) rather than just more places to put the existing ones.
Regards,
--
Rowan Tommins
[IMSoP]
Am 24.03.20 um 15:23 schrieb Rowan Tommins:
On the other hand, this is exactly the kind of thing where strict_types=1 makes things worse - you'll actually get better error output if you use strict_types=0 and pass the string to a function marked as requiring int
no!
with strict_types=0 the casting simp,y happens by the caller and you get
no error at all
Am 24.03.20 um 15:23 schrieb Rowan Tommins:
On the other hand, this is exactly the kind of thing where
strict_types=1 makes things worse - you'll actually get better error
output if you use strict_types=0 and pass the string to a function marked
as requiring int
no!with strict_types=0 the casting simp,y happens by the caller and you get
no error at all
Only if the string is a valid integer; compare https://3v4l.org/uvPYZ with
https://3v4l.org/h1aT5
function foo(int $x) { var_dump($x); }
declare(strict_types=1);
$a = 'hello';
$a = (int)$a; // cast doesn't produce any errors
foo($a); // dumps int(0)
declare(strict_types=0);
$a = 'hello';
foo($a); // TypeError: Argument 1 passed to foo() must be of the type int,
string given
That's what I mean about "stricter casting" - (int)$a basically always
succeeds, so it would be useful to have a version that rejects things like
non-integer strings. That could be Yet Another Runtime Mode using
declare(), but it could just be a different syntax, so that you'd write
this:
// regardless of which strict_types mode you're in
$a = 'hello';
$a = (int!)$a; // TypeError: string value is not valid for strict cast to
type int
foo($a); // statement never reached
Regards,
Rowan Tommins
[IMSoP]