Skip to content

Add ConstantNumericStringType#212

Closed
nobuf wants to merge 1 commit intophpstan:masterfrom
nobuf:nobuf/ConstantNumericStringType
Closed

Add ConstantNumericStringType#212
nobuf wants to merge 1 commit intophpstan:masterfrom
nobuf:nobuf/ConstantNumericStringType

Conversation

@nobuf
Copy link
Copy Markdown
Contributor

@nobuf nobuf commented May 24, 2020

Attempt to fix phpstan/phpstan#3170.

While php treats [1] === ['0' => 1] true and we can always use numeric string offset $array['0'], the below warning sounds reasonable to me:

$array = [1, 2, 3];

// Offset string on array(1, 2, 3) in isset() does not exist.
echo isset($array[$string]) ? $array[$string] : 0;

To keep this current behavior and handle arrays (intentionally) constructed with numeric string differently, this pull request introduces ConstantNumericStringType.

@ondrejmirtes
Copy link
Copy Markdown
Member

ondrejmirtes commented May 24, 2020

Hi, introducing new types has a lot of implications. I don't think we need a new type for >constant strings<, because we can read from the current ConstantStringType if its value is numeric or not.

I'm thinking about introducing general NumericStringType for is_numeric checks (there are issues here about that), but maybe we instead need an accessory intersection type like we have for arrays (array&hasOffset(...)).

Can you please rework this PR without the new type class, and jus asking about whether ConstantStringType::getValue() is numeric or not? Thanks.

@nobuf
Copy link
Copy Markdown
Contributor Author

nobuf commented May 24, 2020

Thanks for the quick reply!

I guess it was confusing that ConstantNumericStringType is inherited from ConstantIntegerType.

Let me explain my current understanding. We can't check is_numeric inside ConstantArrayType::hasOffsetValueType() as the key type would be ConstantIntegerType and it doesn't know if its value was string.

$mappings = [
  '21021200' => 'value', // key type would be ConstantIntegerType
];

I was trying to return new ConstantStringType() in the place I added return new ConstantNumericStringType() in castToArrayKeyType(). Then checking is_numeric in isSuperTypeOf() of ConstantStringType/ConstantIntegerType. But it would break testLiteralArraysKeys etc.

[
  '1' => 'one', // if we treat '1' as ConstantStringType,
  'two', // nextAutoIndex needs to be fixed
  'three',
]

I feel like it'd have many side effects.

I wasn't aware of IntersectionType. Let me check.

@ondrejmirtes
Copy link
Copy Markdown
Member

Hi, it doesn't matter whether some value was a string or not. You simply have an array of array<int, string> (general or literal, doesn't matter) and it's a question whether checking isset($array[$string]) should be marked as a bug or not. Arrays in PHP are messy (https://twitter.com/phpstan/status/1029298522947035136) and can never be fully typesafe.

We can simply change ArrayType::hasOffsetValueType() so that int keys still accept string values. No new type needs to be introduced for this bugfix.

@nobuf
Copy link
Copy Markdown
Contributor Author

nobuf commented May 25, 2020

I'm closing this pull request in favor of #214. Thanks!

@nobuf nobuf closed this May 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Offset string on array(...) in isset() does not exist.

2 participants