Skip to content
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

func_num_args() not usable in mutation-free/pure functions #4215

Closed
colinodell opened this issue Sep 19, 2020 · 2 comments
Closed

func_num_args() not usable in mutation-free/pure functions #4215

colinodell opened this issue Sep 19, 2020 · 2 comments
Labels

Comments

@colinodell
Copy link

colinodell commented Sep 19, 2020

func_num_args() is detected as an impure function which prevents it from being used within a mutation-free or pure function.

In this example, I have a function which needs to differentiate between an optional parameter being explicitly set to null or not being provided at all: https://psalm.dev/r/2c0112de69

Psalm is technically correct that func_num_args() is impure since its output is not a function of its input. However, I believe that my outer getValue() function is pure since its output only relies on the parameters passed in.

Should Psalm therefore make an exception to allow the impure func_num_args() function to be called within other pure functions?

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/2c0112de69
<?php

/**
 * @param array<string, mixed> $arr     Data to pull the value from
 * @param string               $key     The key where the value should exist
 * @param mixed|void           $default Optional default value to return (can be null)
 *
 * @return mixed
 *
 * @psalm-pure
 */
function getValue(array $arr, string $key, $default = null) {
    $hasDefault = \func_num_args() === 3;
    
    if (\array_key_exists($key, $arr)) {
        return $arr[$key];
    }
    
    if ($hasDefault) {
        return $default;
    }
    
    throw new RuntimeException('Key does not exist and no default value was given');
}

$data = ['foo' => 'bar'];

assert(getValue($data, 'foo') === 'bar');
assert(getValue($data, 'qwerty', 42) === 42);
assert(getValue($data, 'asdf', null) === null);

try {
    $x = getValue($data, 'asdf');
    assert(false); // Exception should be thrown before this point
} catch (RuntimeException $ex) {
    assert(true); // Yay the exception was thrown!
}
Psalm output (using commit 5db75df):

ERROR: ImpureFunctionCall - 13:19 - Cannot call an impure function from a mutation-free context

INFO: MixedAssignment - 33:5 - Unable to determine the type that $x is being assigned to

INFO: UnusedVariable - 33:5 - Variable $x is never referenced

@muglug muglug added the bug label Sep 19, 2020
@muglug
Copy link
Collaborator

muglug commented Sep 19, 2020

Yeah, it doesn't seem impure in any context really

@muglug muglug closed this as completed in 94ed53b Sep 19, 2020
muglug added a commit that referenced this issue Oct 7, 2020
danog pushed a commit to danog/psalm that referenced this issue Jan 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants