Override PHP docblock/annotation of method without

2019-07-25 17:12发布

问题:

This is a question about the autocompletion behavior in PhpStorm (and possibly other IDEs) in conjunction with PHP docblocks.

I have to groups of classes in my application. First there are individual classes for various products (CarProduct, FoodProduct etc.), all inheriting from BaseProduct, and the counterpart for individual contracts (CarContract, FoodContract etc.), all inheriting from BaseContract.

<?php

class BaseContract
{
    /** @var BaseProduct */
    private $product;

    /**
     * @return BaseProduct
     */
    public function getProduct()
    {
        return $this->product;
    }
}

Now I have an instance of CarContract, and I wanna get some CarProduct specific information:

<?php

/* PhpStorm thinks, this is BaseProduct */
$product = $carContract->getProduct();

/* hence, getSpeed() is not available for PhpStorm */
$product->getSpeed();

The autocompletion is not working as I like. There are two workarounds for this, but both are not nice:

  1. Overload getProduct() in the subclass, just with updated @return docblocks
  2. Add /** @var CarProduct $product */ everywhere, where I access the product of a CarContract

Is there a "usual" way to solve something like this, or are my workarounds the only solutions?

回答1:

PhpStorm does not really allow/does not support doing something like: have the same named class defined elsewhere and just use it as a reference for overriding definitions of real class. You can do that .. but IDE will warn with "multiple definitions of the same class" and it may introduce some weird behaviour/unexpected warnings...

Here is a ticket that ask for such feature: https://youtrack.jetbrains.com/issue/WI-851 -- watch it (star/vote/comment) to get notified on any progress.


Your options are: you can provide correct type hint locally (to local variable) using @var -- you already know it and that's first that you would think of:

<?php

/** @var \CarProduct $product */
$product = $carContract->getProduct();

$product->getSpeed();

Another possible way: instead of overriding actual method .. you can try doing the same but with @method PHPDoc -- will work with your code:

<?php
/**
 * My Car Product class
 * 
 * @method \CarProduct getProduct() Bla-bla optional description
 */
class CarContract extends BaseContract ...