1

I have the following code and want to get it through Psalm static checks:

if (
    empty($sessions[$token]->product)
    || !is_object($sessions[$token]->product)
) {
     continue;
}

if (
    empty($sessions[$token]->product->view_list)
    || !is_array($sessions[$token]->product->view_list)
) {
    continue;
}

foreach ($sessions[$token]->product->view_list as $view) {
    if (!($view instanceof stdClass) || empty($view->color_list) || !is_array($view->color_list)) {
        continue;
    }
    ...

I am getting

ERROR: MixedAssignment
at ...
Unable to determine the type that $view is being assigned to (see https://psalm.dev/032)
                foreach ($sessions[$token]->product->view_list as $view) {

As you can see I tried in the foreach to already ensure the type of $view (it comes from an external API), but Psalm is not convinced.

I also tried a type annotation /** @var stdClass $view */ but this does not seem right and also not work.

EDIT: if I use a typehint, phpstan complains to use an assert. I also don't want to use an assert, because it would break the flow, I want to continue instead.

Luuk
  • 12,245
  • 5
  • 22
  • 33
Alex
  • 32,506
  • 16
  • 106
  • 171

2 Answers2

1

Try this:

if (
    empty($sessions[$token]->product->view_list)
    || !is_array($sessions[$token]->product->view_list)
) {
    continue;
}

//* @var array $list */
$list = $sessions[$token]->product->view_list;

foreach ($list as $view) {
    if (!($view instanceof stdClass) || empty($view->color_list) || !is_array($view->color_list)) {
        continue;
    }
    ...

Read more: https://psalm.dev/articles/easier-to-diagnose-mixed-issues

  • Okay, that basically works. but if I still keep the actual check (to continue in case the input is wrong), I get `Docblock-defined type stdClass for $view is always stdClass (see https://psalm.dev/155) if (!($view instanceof stdClass) || empty($view->color_list) || !is_array($view->color_list)) {` – Alex Aug 31 '23 at 12:04
  • So $list is an array of unknown type. You should mark it as /** @var array $list */ Then you check if $view is instance of stdClass. – Jakub Kleban Aug 31 '23 at 12:11
  • Mh, the problem I am seeing is, that as soon as I use a docblock, it says my check for the actual type is redudant, but of course the doc block does not check anything, so I want to prefer a real check ... – Alex Aug 31 '23 at 15:23
0

So this seems to make psalm (and myself, coworkers, customer) happy:

$list = $sessions[$token]->product->view_list ?? [];

if (!is_array($list)) {
    continue;
}

/** @var mixed $view */
foreach ($list as $view) {
    if (!($view instanceof stdClass) || empty($view->color_list) || !is_array($view->color_list)) {
        continue;
    }

But PHPStorm complains about the @var mixed $view ... hmm .. okay

Alex
  • 32,506
  • 16
  • 106
  • 171