Skip to content

fix parameter of strval, intval and floatval #1005

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: 1.5.x
Choose a base branch
from

Conversation

Khartir
Copy link
Contributor

@Khartir Khartir commented Feb 8, 2022

resolves phpstan/phpstan#6560

I implemented a rule instead of a dynamic return type extension as mentioned in phpstan/phpstan#6560 (comment). I think that was a misunderstanding? After all the problem is the parameter type, not the return type of the function. For the return type StrvalFamilyFunctionReturnTypeExtension already exists.

class StrvalFamilyParametersRule implements Rule
{

private const FUNCTIONS = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about boolval?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not aware of any restrictions on boolval. As far as I know it really accepts mixed. Am I missing something?

Also I think I wiill remove everything but strval. Only strval needs special handling due to Stringable. Everything else should be fixable by changing the function signature in functionMap.

@ondrejmirtes
Copy link
Member

Errr, I thought that you want to implement a dynamic return type extension so that the result type of floatval($val) is the same as (float) $val.

If you need to check the parameter type then sure, a change in functionMap would be sufficient.

@Khartir Khartir force-pushed the fix-strval-parameter branch from 5ea3402 to 1073a5e Compare February 10, 2022 18:19
Comment on lines +67 to +71
$base = new ObjectType('');

if ($type instanceof ErrorType || !$base->isSuperTypeOf($type)->maybe()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way, to check if this is an instance of any object?

@Khartir
Copy link
Contributor Author

Khartir commented Feb 10, 2022

After changing the functionMap I had to completely rewrite the rule to only check Stringable objects, since intval and floatval accept string, but no objects.

@Khartir Khartir force-pushed the fix-strval-parameter branch 2 times, most recently from 86408aa to cc28967 Compare February 10, 2022 18:42
@@ -2020,7 +2020,7 @@
'DomXsltStylesheet::result_dump_mem' => ['string', 'xmldoc'=>'DOMDocument'],
'DOTNET::__construct' => ['void', 'assembly_name'=>'string', 'class_name'=>'string', 'codepage='=>'int'],
'dotnet_load' => ['int', 'assembly_name'=>'string', 'datatype_name='=>'string', 'codepage='=>'int'],
'doubleval' => ['float', 'var'=>'mixed'],
'doubleval' => ['float', 'var'=>'array|bool|float|int|resource|string|null'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ever useful to allow the array and resource here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also a bit confused - doubleval does not accept object here which should already be picked up by an existing rule (CallToFunctionParametersRule) but apparently isn't. Any idea why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ever useful to allow the array and resource here?

Probably not. I was attempting to keep (float) and floatval() in line and used the actual PHP behavior as a guideline along with the fact that casting to int is possible.

I'm also a bit confused - doubleval does not accept object here which should already be picked up by an existing rule (CallToFunctionParametersRule) but apparently isn't. Any idea why?

I have to check again, but if I remember correctly, it does pick up regular objects, but has a special rule to allow objects with a __toString-method. Which in general is the correct behavior. intval and floatval are the special case, in that they accept string but not Stringable:

php > $stringable = new class() {public function __toString(): string {return '';}};
php > echo strlen($stringable);
0
php > echo intval($stringable);
PHP Notice:  Object of class class@anonymous could not be converted to int in php shell code on line 1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a commit to forbid casting resource to float. I'm looking into doing the same with array but that causes a regression for phpstan/phpstan#5162.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I looked into phpstan/phpstan#5162. The problem is, that the fix for that issue was to explicitly allow casting array to float. If we forbid it here again, this will obviously fail again. In order to resolve this, the underlying issue would have to be resolved:

/** @var array<string,string|array<string>> $result */
$result = $this->Get();
if ( array_key_exists('a',$result) && ! is_numeric( $result['a'] ) )
{
	exit(1);
}
assertType('numeric-string', $result['a']); //this currently reports 'array<string>|string'

/** @var array<string,string|array<string>> $result2 */
$result2 = $this->Get();
if ( ! is_numeric( $result['a'] ) )
{
	exit(1);
}
assertType('numeric-string', $result['a']); //this works

As far as I can tell in the first case the resolved type of $result['a'] is not updated, because it might not even exist. Obviously the type of $result['a'] could also be ERROR if the offset doesn't exist.
However I have no idea how to fix this.

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.

Handle different ways to cast the same
3 participants