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

psalm not understanding properties-of<Class> assignment to a ParentClass property, if properties-of<ParentClass> is used #10994

Open
juacala opened this issue May 28, 2024 · 1 comment

Comments

@juacala
Copy link

juacala commented May 28, 2024

psalm does not recognize the properties-of<Class> type if it's assigned to a property of a class, and then it gets fetched using properties-of

See: https://psalm.dev/r/e76bd1defd

<?php

// Class we'll load properties-of into a property of another class
class DBLoginInfo
{
    /**
     * @param string $host 
     * @return void 
     */
    public function __construct(
        public string $host
       )
       {}
}

// Load in properties one way
class DBConnectInfoAsArray
{
    /**
     * @param properties-of<DBLoginInfo> $read
     */
    public function __construct(
        public array $read
    )
    {}
}

// Load in properties another way
class DBConnectInfoAsArray2
{
    /** @param properties-of<DBLoginInfo> */
    public array $read;
    public function __construct(array $read)
    {
        $this->read = $read;
    }
}

/**
* Fail: Try to access host from first parent class
* @param properties-of<DBConnectInfoAsArray> $info
* @return void
*/
function blah(array $info)
{
    $read = $info['read'];
    echo $read['host'];
}

/**
* Fail: try to access host from second parent class
* @param properties-of<DBConnectInfoAsArray2> $info
* @return void
*/
function blah2(array $info)
{
    $read = $info['read'];
    // This says it's just a generic array... it doesn't seem to understand the docblock type
    echo $read['host'];
}

/**
* Pass if you explicitly assign @var
* This one works by using @var to tell it what it should be, but it seems
*   like psalm should have been able to tell what it is without using an @var
* @param properties-of<DBConnectInfoAsArray2> $info
* @return void
*/
function blah3(array $info)
{
    /** @var properties-of<DBLoginInfo> */
    $read = $info['read'];
    echo $read['host'];
}

/**
* Pass if you don't use properties-of<DBConnectInfoAsArray>, and load the class itself.
* @return void
*/
function blah4(DBConnectInfoAsArray $info)
{
    $read = $info->read;
    echo $read['host'];
}
Copy link

I found these snippets:

https://psalm.dev/r/e76bd1defd
<?php

// Class we'll load properties-of into a property of another class
class DBLoginInfo
{
    /**
     * @param string $host 
     * @return void 
     */
    public function __construct(
        public string $host
       )
       {}
}

// Load in properties one way
class DBConnectInfoAsArray
{
    /**
     * @param properties-of<DBLoginInfo> $read
     */
    public function __construct(
        public array $read
    )
    {}
}

// Load in properties another way
class DBConnectInfoAsArray2
{
    /** @param properties-of<DBLoginInfo> */
    public array $read;
    public function __construct(array $read)
    {
        $this->read = $read;
    }
}

/**
* Fail: Try to access host from first parent class
* @param properties-of<DBConnectInfoAsArray> $info
* @return void
*/
function blah(array $info)
{
    $read = $info['read'];
    echo $read['host'];
}

/**
* Fail: try to access host from second parent class
* @param properties-of<DBConnectInfoAsArray2> $info
* @return void
*/
function blah2(array $info)
{
    $read = $info['read'];
    // This says it's just a generic array... it doesn't seem to understand the docblock type
    echo $read['host'];
}

/**
* Pass if you explicitly assign @var
* This one works by using @var to tell it what it should be, but it seems
*   like psalm should have been able to tell what it is without using an @var
* @param properties-of<DBConnectInfoAsArray2> $info
* @return void
*/
function blah3(array $info)
{
    /** @var properties-of<DBLoginInfo> */
    $read = $info['read'];
    echo $read['host'];
}

/**
* Pass if you don't use properties-of<DBConnectInfoAsArray>, and load the class itself.
* @return void
*/
function blah4(DBConnectInfoAsArray $info)
{
    $read = $info->read;
    echo $read['host'];
}
Psalm output (using commit 16b24bd):

ERROR: InvalidArrayAccess - 47:10 - Cannot access array value on non-array variable $read of type properties-of<DBLoginInfo>

INFO: MixedArgument - 47:10 - Argument 1 of echo cannot be mixed, expecting string

INFO: PossiblyUndefinedStringArrayOffset - 59:10 - Possibly undefined array offset ''host'' is risky given expected type 'array-key'. Consider using isset beforehand.

INFO: MixedArgument - 59:10 - Argument 1 of echo cannot be mixed, expecting string

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

No branches or pull requests

1 participant