1

Is it possible to type hint a parameter directly inline during a function call?

public function load(ObjectManager $manager)
{
    $product = $this->createProduct(
        "T-SHIRT",
        $this->getReference('brand-4') /** @var Brand <=== NOT WORKING */ 
    );
    $manager->persist($product);
    $this->addReference('product-1', $product);
}

/**
 * @param string $name
 * @param Brand  $brand
 */
private function createProduct($name, $brand)
{
    $product = new Product();
    $product
        ->setName($name)
        ->setBrand($brand) // <== this setter needs a Brand entity
    ;

    // [...]
}

Of course phpstan is giving me an error because getReference returns an object and the function expects a Brand object:

Parameter #2 $brand of method AppBundle\DataFixtures\ORM\ProductFixtures::createProduct() expects AppBundle\Entity\Brand, object given.

I would NOT like to explicity declare a variable like this:

/** @var Brand */
$brand = $this->getReference('brand-4');
$product = $this->createProduct(
    "T-SHIRT",
    $brand
);

It would save me a lot of time!

StockBreak
  • 2,857
  • 1
  • 35
  • 61
  • 1
    Why not changing `createProduct` hint? – glinda93 Mar 05 '20 at 16:42
  • Because `createProduct` will call `setBrand` on a newly created `Product` object and it expects a `Brand` entity. – StockBreak Mar 05 '20 at 16:43
  • 1
    I see, the `getReference` returns various types of class according to reference, so you cannot hint its return type. But you are sure that it will return a `Brand` object from `brand-4` so you want a way to hint this type in-line. – glinda93 Mar 05 '20 at 16:49
  • @bravemaster exactly! – StockBreak Mar 05 '20 at 16:50
  • A workaround would be to change the `createProduct` hint anyway, and use `instanceof` in it to assert you have a `Brand` but I guess it's not much better than defining a variable. On another hand it could allow you to make sure `getReference`'s return is indeed a `Brand` and manage the errors. – Altherius Mar 05 '20 at 16:50
  • Looks a like a duplicate of https://stackoverflow.com/questions/3243900/convert-cast-an-stdclass-object-to-another-class and I think you could do something like this: `$brand = (Brand) $this->getReference('brand-4');` – beltouche Mar 05 '20 at 16:53
  • Why does `$this->getReference` returns something different other than Brand? – Cadu De Castro Alves Mar 05 '20 at 16:55
  • @Altherius the `getReference` is not a method of mine, it's from the fixtures bundle. @beltouche I know how to cast an object, this is not my problem. I just would like to type hint inline without using an additional variable. – StockBreak Mar 05 '20 at 16:56
  • @beltouche Look the question carefully. You cannot use that style for custom classes. – glinda93 Mar 05 '20 at 16:57

1 Answers1

1

I had the same problem implementing a generic like structure. This solution works when you want to override method signature. You can accomplish this using @method doc comments but you need 2 classes for it:

class AbstractRepository {
  /**
   * @param mixed $id
   * @return object
   */
  public function getReference($id) {
     /* ... */
  }
}

/**
 * @method ConcreteResult getReference($id)
 */
class ConcreteRepository extends AbstractRepository {

}

$repo = new ConcreteRepository();
$repo->getReference(123); // Has ConcreteResult return type

This works in PHPStorm for example. I have not checked if it works with PHPStan.

Code Spirit
  • 3,992
  • 4
  • 23
  • 34