PHPDoc for conditional polymorphic call

114 Views Asked by At

For $item there's a polymorphic loggable relationship. In the database this is stored in items as loggable_type and loggable_id (for PHP 8+ in and Laravel).

for($items as $item) {
    // ...

    if ($item->loggable_type === Comment::class) {
        $item->loggable->resetDates();
    }

    // ...
}

I'm trying to type hint that loggable within the condition is a Comment. I think I might be able to user @var but doing something like /* @var $item->loggable Comment */ doesn't work and I can't do /* @var $item Comment */ since that sets it to $item and not its property.

I'm thinking of changing the condition to if ($item->loggable instance of Comment), however I'd rather not since that requires loading and creating the Comment even if it's not used.

Is there a way to type hint $item->loggable as Comment?

2

There are 2 best solutions below

0
Justinas On

Assign it to variable

for($items as $item) {
    if ($item->loggable_type === Comment::class) {
        /** @var Comment $loggable */
        $loggable = $item->loggable;
        
        $loggable->resetDates();
    }
}
1
matiaslauriti On

As @Justinas stated, either assign it to a variable:

for ($items as $item) {
    if ($item->loggable_type === Comment::class) {
        /** @var Comment $loggable */
        $loggable = $item->loggable;
        
        $loggable->resetDates();
    }
}

Or set the possible values you could have (if they are fixed and known) on the model itself like this:

/**
 * @property Comment|WhateverModel|Model $loggable
 */
class Item extends Model
{
   // ...
}

That will tell the IDE that the property loggable is possibly a Comment object, WhateverModel object, or Model object (so you still have normal Model's methods auto-completion).

If you can narrow down which classes you could have there, then add them, else I would go with the first option (assign a value and use a PHPDoc block for a variable)