2017-11-17 15 views
2

シナリオ私は私の関数は戻り値の型Cityを持っていると言うことPHP7タイプヒンティングを使用していPhpStormは別の

の延長として戻り値の型を認識しません。

public function getCityById(int $city_id) : City { ... } 

この関数では、ファインダを実行した結果を返します。

return $this->city_finder->findById($city_id); 

しかしfindById()機能がAbstractModelを返すためPhpStormは、ここに文句を言います。

しかし、私はclass City extends AbstractModelですが、これは問題ではありません。しかし、PhpStormはこれを認識していないようであり、警告文を強調表示します。

重要な警告であるため、このタイプの警告(検査を無効にする)をミュートしたくありません。

質問

私はPhpStormこのreturn文が戻り値の型を満足することを認識させることができますか?

追加情報

回避策の一つは、変数を抽出し、それに注釈を付け、そのようにすることです。この時点で

/** @var City $city */ 
$city = $this->city_finder->findById($city_id); 
return $city; 

、それはそれについて私に警告し停止しますが、それはのように思えます余分な行は、IDEで警告をミュートするためだけに存在するため、回避する必要があります。

ファンクションクラスがモデルごとに生成されるため、findById()関数は間違った型を返さないように保護されています。

$this->city_finder = $this->orm->getFinder(City::class); 
//... 
$city = $city_finder->findById(...); 
+0

あなたの 'city_finder'クラスの' findById() 'メソッドのシグニチャを(そのクラスのPHPDocコメントの' @ method'タグを使って)オーバーライドし、このメソッドが具体的な 'City'クラスを返すようにすることができます://stackoverflow.com/a/43112745/783119)。もう1つのアイデア - https://stackoverflow.com/a/44913283/783119(ここにも当てはまるかどうかわからない) – LazyOne

答えて

4

PHPStormが正しい。

あなたfindById()戻りAbstractModelCityあなたが返すようにしようとしているということが、より広範です。 findById()からもAbstractModelから継承されていますが、Cityまたはその子孫ではない他のクラスから受け取った場合、PHPから致命的なエラーが発生し、PHPStormが警告しているものです。

これを回避するには、すでに行ったようにアノテーションを追加するか、if ($city instanceof City) {return $city; }を明示的にチェックします。実行時に安全であることによって、少し肥大して見えるかもしれません。

+0

実際には、私のFinderクラスはモデルごとに生成されるので。例えば。 '$ finder = $ orm-> getFinder(City :: class);'。しかし、PHPStormがこれを検出することは非常に難しいことがわかります。 – Alec

+0

@Alecそれは、PHPStormが知ることは非常に難しいことではありません。そのORMの特別なルールなしには不可能です。タイプ・システムに関しては、 'City :: class'はコンストラクタで使用している文字列であり、構築されたオブジェクトのタイプは変更されません。 – IMSoP

+0

@IMSoP True .. PhpStormの[高度なメタデータ機能性](https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata)は他のケースで役立っています...しかし、私はそれがここで何かをするとは思っていません(これは別の方法で動作するので、 '$ finder'は' City'と 'Area'の同じクラスインスタンスであり、すべてのニュアンス(差分)を内部的に保持します。 – LazyOne

3

PHPStormは技術的には右です:あなたの関数の契約に従って、ステートメントは間違った値を返すかもしれません。

$result = $this->city_finder->findById($city_id); 

我々はここについて$resultを知ることができる唯一のことは、findByIdが私たちを約束するもので、それはそれはAbstractModelだということです。 Cityとなりますが、User、またはWidget、またはclass extends AbstractModel {}と定義される匿名オブジェクトであってもかまいません。

根本的な問題は、$this->city_finderがいくつかの抽象リポジトリのインスタンスであることです。 は常にCityのオブジェクトを処理することを認識していますが、これは実際にタイプシステムに組み込まれていません。より具体的なクラスであれば、findByIdメソッドからCityオブジェクトが返されたことを宣言することができ、コードは型保証されます。

:あなたのORMは、パラメータ( $finder = $orm->getFinder(City::class);)としてクラス名を取り込みPHPは「ジェネリック」または「テンプレートメタプログラミング」をサポートしている場合、あなたはこのような何かを書くかもしれないあなたのコメントに基づいて


class ORM { 
    public function getFinder<T>(): Finder<T> { ... } 
} 
class Finder<T> { 
    public function findById(int $id): T { ...} 
} 
$finder = $orm->getFinder<City>(); 
$city = $finder->findById($city_id); 

$finderFinder<City>のインスタンスであることをアナライザは知っているので、findByIdCityを返します。

ジェネリックスがないと、コンストラクタにCity::classが指定されている場合、Finderクラスは常にそのクラスのインスタンスを返すことをアナライザに伝える方法はありません。