Matt Gibson
Matt Gibson

Reputation: 14949

In PHPStorm, how can I make type hinting work when I have a superclass method that returns a different type from each subclass

I have a class that is inheriting from a superclass and where the superclass has a static find() method that instantiates instances of the subclass (active record pattern).

class ActiveRecordClass {

    /**
     * @return mixed
     */
    public static function find() {
        // Code returns instance of called class
    }
}

class ModelClass extends ActiveRecordClass {

}

// returns instance of ModelClass, but PHPStorm doesn't realise
ModelClass::find($model_id); 

At the moment, the docblock is not much good for code completion and type hinting. I can't use the superclass as a return type as the subclasses have different methods due to DB columns.

How can I indicate to PHPStorm that the superclass find() method returns an instance of the subclass it's called from, so that code completion works?

Upvotes: 9

Views: 2393

Answers (2)

Matt Gibson
Matt Gibson

Reputation: 14949

Found it:

class ActiveRecordClass {

    /**
     * @return static
     */
    public static function find() {
        // Code returns instance of called class
    }
}

It seems that @return self vs @return static works the same way that you would expect given what the keywords normally do. @return self did not pick up the methods available on the concrete subclass, but @return static make autocomplete work great.

Upvotes: 10

Vasiliy vvscode Vanchuk
Vasiliy vvscode Vanchuk

Reputation: 7159

/**
* @var ModelClass
**/ 
$model = ModelClass::find($model_id);

like that - set variable type with phpDoc

Also http://phpdoc.org/docs/latest/references/phpdoc/types.html say that you can use 'self' as type of returning value

13 self, the element to which this type applies is of the same Class, or any of its children, as which the documented element is originally contained.

For example:

Method C() is contained in class A. The DocBlock states that its return value is of type self. As such method C() returns an instance of class A. This may lead to confusing situations when inheritance is involved.

For example (previous example situation still applies):

Class B extends Class A and does not redefine method C(). As such it is possible to invoke method C() from class B. In this situation ambiguity may arise as self could be interpreted as either class A or B. In these cases self MUST be interpreted as being an instance of the Class where the DocBlock containing the self type is written or any of its child classes.

In the examples above self MUST always refer to class A or B, since it is defined with method C() in class A.

If method C() was to be redefined in class B, including the type definition in the DocBlock, then self would refer to class B or any of its children.

so try

/**
 * @return self
 */
public static function find() {
    // Code returns instance of called class
}

Upvotes: 0

Related Questions