You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHPStan提示Cannot access property on mixed,已验证仍报错求助

PHPStan 报错:无法访问 mixed 类型的属性(已通过自定义函数验证)

代码示例

主逻辑代码

$decodedCredentials = json_decode($credentials, false);

if (!$this->isValidCredentials($decodedCredentials)) {
    return null;
}

$credential = new Credential();
$credential->username = $decodedCredentials->username;
$credential->password = $decodedCredentials->password;
$credential->line = $decodedCredentials->line;

验证函数代码

private function isValidCredentials(mixed $credentials): bool
{
    if (!is_object($credentials)) {
        return false;
    }

    return is_object($credentials) &&
        property_exists($credentials, 'username') &&
        property_exists($credentials, 'password') &&
        property_exists($credentials, 'line');
}

PHPStan 报错信息

------ -------------------------------------------- 
  Line   Authentication.php                           
 ------ -------------------------------------------- 
  :146   Cannot access property $username on mixed.  
  :147   Cannot access property $password on mixed.  
  :148   Cannot access property $line on mixed.      
 ------ -------------------------------------------- 

问题说明

代码逻辑上已经通过isValidCredentials验证了$decodedCredentials是包含指定属性的对象,但PHPStan仍报错。不想把校验逻辑移到当前函数,询问是否遗漏了配置或这是PHPStan的Bug。

原因与解决方案

这不是PHPStan的Bug,而是静态分析的局限性:PHPStan无法自动追踪自定义函数的返回值与输入参数之间的类型关联,它不知道isValidCredentials返回true时,输入的$credentials一定是包含指定属性的对象。

解决方法是通过类型断言注解明确告知PHPStan验证通过后参数的类型结构:

方案1:给验证函数加注解

修改验证函数的注释,使用PHPStan的断言注解:

/**
 * @phpstan-assert object{username: mixed, password: mixed, line: mixed} $credentials
 */
private function isValidCredentials(mixed $credentials): bool
{
    if (!is_object($credentials)) {
        return false;
    }

    return is_object($credentials) &&
        property_exists($credentials, 'username') &&
        property_exists($credentials, 'password') &&
        property_exists($credentials, 'line');
}

方案2:在验证后添加局部类型断言

如果不想修改验证函数,可以在验证通过后,给$decodedCredentials添加局部类型注解:

if (!$this->isValidCredentials($decodedCredentials)) {
    return null;
}

/** @var object{username: mixed, password: mixed, line: mixed} $decodedCredentials */
$credential = new Credential();
$credential->username = $decodedCredentials->username;
// ... 其他属性赋值

若$username/$password/$line有明确类型(如string),可将mixed替换为对应类型,让类型检查更严格。

内容的提问来源于stack exchange,提问作者CoderJoe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 21:55:01