Skip to content

Operations that update the type of one array key affect all keys when the arrays doesn't have type information #4926

@DeveloperRob

Description

@DeveloperRob

This is best explained by the demo, but if you have an array for which phan can not determine the types (e.g. decoded from a JSON string), the first operation that returns a type (e.g. where phan knows a certain array key at that point is a certain type), it sets the type to an ArrayShapeType with that type only. This then means that operations on different keys can fail due to a type mismatch.

Potentially related, is that if the loop is removed, after the first operation on the array, phan then believes that key is the only key that exists. With this, provides information on the structure of the array resolves the feedback that the second array key is not defined, but the strlen seems to override the type information provided in the comment.

Test code 1:

<?php
class Foo{
	public function __construct(string $bar){
		$barArr = json_decode($bar, true);
		//'@phan-var list<array{x:string,y:string}> $barArr'; // If this is uncommented, phan provides no output
		foreach($barArr as $barRow){
			$barRow["x"]	= \strlen($barRow["x"]);
			$barRow["y"]	= \strlen($barRow["y"]);
		}
	}
}

Expected output: None
Actual output:

test2.php:7 PhanTypeMismatchArgumentInternal Argument 1 ($string) is $barRow['y'] of type int but \strlen() takes string

Test code 2:

<?php
class Foo{
	public function __construct(string $bar){
		$barArr			= json_decode($bar, true);
		if(count($barArr) > 0){ // Needed so phan knows that $barArr[0] is set
			$barArr[0]["x"]	= \strlen($barArr[0]["x"]); // Changing this to echo $barArr[0]["x"]; causes no output as expected
			$barArr[0]["y"]	= \strlen($barArr[0]["y"]);
		}
	}
}

Expected output: None
Actual output:

test2.php:7 PhanTypeInvalidDimOffset Invalid offset "y" of $barArr[0] of array type array{x:int}
test2.php:7 PhanTypeMismatchArgumentInternal Argument 1 ($string) is $barArr[0]['y'] of type null but \strlen() takes string

Test code 3:

<?php
class Foo{
	public function __construct(string $bar){
		$barArr			= json_decode($bar, true);
		'@phan-var list<array{x:string,y:string}> $barArr';
		if(count($barArr) > 0){ // Needed so phan knows that $barArr[0] is set
			$barArr[0]["x"]	= \strlen($barArr[0]["x"]); // Changing this to echo $barArr[0]["x"]; causes no output as expected
			$barArr[0]["y"]	= \strlen($barArr[0]["y"]);
		}
	}
}

Expected output: None
Actual output:

test2.php:8 PhanTypeMismatchArgumentInternal Argument 1 ($string) is $barRow['y'] of type int but \strlen() takes string

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions