型パラメーターを受け取る抽象クラスを作成したいと思います。そのクラスのコンストラクターには別の Action を渡す必要があります。
abstract class Action<Tc> {
public function __construct(private ?Action<*> $onSuccess = null) {}
}
型パラメーターのワイルドカードを表現するにはどうすればよいですか。「?」(Java) または "_" (Scala) ハック?
現在、ハックにはワイルドカード型パラメーターがありません。そのため、実際には必要のないダミーの型パラメーターを実際に指定するのが最も近い方法です。たとえば、次のようになります。
abstract class Action<Tc, Ta> {
public function __construct(private ?Action<Ta> $onSuccess = null) {}
// ...
}
$onSuccess
メンバー変数をどのように正確に使用するかに応じて、Action<T>
後で決定される特定のサブクラスにする必要がある場合があるため、次のようなものが必要になる場合があります。
abstract class Action<Tc, Ta, To as Action<Ta>> {
public function __construct(private ?To $onSuccess = null) {}
// ...
}
ただし、上記の「ダミー」タイプが本当にダミーであるかどうかは疑問です。 のユースケースの大部分は、がAction<T>
正確に何であるかを気にしT
ますAction<T>
。(コールサイトで を気にしないというまれなケースは確かにありますがT
、それはまれなので、この機能を構築する際に、実際にそれがあなたのケースであるかどうかを検討することをお勧めします。)
ワイルドカードについてはよくわかりませんが、これで目的を達成できますか?
<?hh
abstract class Action<T1 as Action, T2> {
public function __construct(private ?T1 $onSuccess = null, private ?T2 $bla = null) {}
}
class ActionA<T1 as Action, T2> extends Action<T1, T2> {}
class ActionB<T1 as Action, T2> extends Action<T1, T2> {}
class ActionC<T1 as Action, T2> extends Action<T1, T2> {}
$action = new ActionA(new ActionB(new ActionC(null)));
var_dump($action);
これを HHVM 3.1.0 に対して実行すると、次のようになります。
object(ActionA)#1 (2) {
["onSuccess":"Action":private]=>
object(ActionB)#2 (2) {
["onSuccess":"Action":private]=>
object(ActionC)#3 (2) {
["onSuccess":"Action":private]=>
NULL
["bla":"Action":private]=>
NULL
}
["bla":"Action":private]=>
NULL
}
["bla":"Action":private]=>
NULL
}
また、3.1.0 型チェッカーも「エラーなし!」を返します。
ただし、T1 as Action
抽象クラスに関するステートメントは強制されているようには見えません。たとえば、インスタンス化行を次のように変更できます。
$action = new ActionA(new ActionB(new ActionC(new DateTime())));
そして、タイプチェッカーはまだエラーを返さずに、問題なく動作します。そして、これはクラス定義を独自のファイルに取り出した後です<?hh // strict
.
本当にあなたの答えではありませんが、おそらく近いですか?上記の動作は、ハックがこの種のパターンに問題を抱えていることを示唆しているでしょうか?