2
votes

Why does this work:

/* @var $foo ClassName */
$foo->someFunction();

but this one not:

/* @var $this->foo ClassName */
$this->foo->someFunction();

Here's the complete setup:

abstract class Bar
{
  $foo = null;
}


class Cool
{
  // some function sets $this->foo

  public function doSthWithFoo() // does not work
  {
    /* @var $this->foo ClassName */
    $this->foo->someFunction();
  }

  public function doSthWithFoo2() // works just fine
  {
    $test = $this->foo
    /* @var $test ClassName */
    $test->someFunction();
  }
}

Another approach would be to define the $foo variable in the new class again:

class Cool
{
  /* @var $foo ClassName */
  $foo = null;

  // ...
}

Of cource the PHP code is executed properly, but the PHPDoc is buggy.

(PhpStorm 2018.2.2)


Thanks in advance!

2
Docblock the abstract class, this should give you better results - Dale
"but the PHPDoc is buggy." It's NOT buggy. You just trying to create your own rules of how PHPDoc should work. But it does NOT work that way -- as simple as that. You cannot typehint specific sub entity using @var -- only top level/whole entity. So it's what Dale have said .. or you can try @property tag in your Cool class. - LazyOne
@Dale / @LazyOne: Yes, but that's not possible in this case. In this case the abstract class' $foo property has no type until a class inherits it and sets its specific type. The intention is to 'force' using the inherited $foo property instead of creating lots of different properties... (but as you said that's beyond this question) @LazyOne: You're right, PHPDoc is not buggy, but it would be kind of awesome if that worked. - Flo Bayer
Take a look into phpstorm.meta files, they might not be the solution but I believe they may help somewhat, ill try to get a link for you - Dale

2 Answers

2
votes

I cannot answer your question directly as I do not know why that doesn't work but I normally do this to get around the situation

<?php

class foo
{
    /** @var SomeClass $foo */
    protected $foo;

    // the rest of the class
}

And now you should get the proper code completion for $this->foo->availableThings()

1
votes

I want to try to explain by code below:

class Foo
{
    public function myFooFunction()
    {
        return 'this is foo function';
    }
}

class Bar
{
    public $foo;

    public function __construct(Foo $foo)
    {
        $this->foo = $foo;
    }

    public function myBarFoonction()
    {
        return 'this is bar function';
    }
}

$foo = new Foo();
echo $foo->myFooFunction(); //call in Foo object

$bar = new Bar($foo);
echo $bar->myBarFoonction(); // call in Bar object
echo $bar->foo->myFooFunction(); // call in Foo object 

if you call $bar->foo - you must call function in that object