3

私は PHP プロジェクトを Hack に変換する過程にあり、ちょっとした障害に遭遇しました。私がやろうとしているのは、IoC コンテナーを PHP から Hack に書き直すことです。すべてを Hack タイプ チェッカー ツールに渡すのに少し苦労しています。

つまり、基本的に私が持っているのは、文字列をクロージャ マッピングに登録できるコンテナです。アイデアは、クロージャーにクラスをインスタンス化するロジックが含まれているということです。コンテナーは、作成したインスタンスも格納し、新しいインスタンスを強制的に作成することもできます。ここに私のコンテナコードがあります:

<?hh // strict
class Container {
    private Map<string, mixed> $instances = Map {};
    private Map<string, (function (Container): mixed)> $registered = Map {};

    public function register(string $alias, (function (Container): mixed) $closure): void
    {       
        $this->registered[$alias] = $closure;
    }

    public function get(string $alias): ?mixed
    {
        if (!$this->registered->contains($alias)) {
            return null;
        }

        $instance = $this->instances->get($alias);
        if ($instance !== null) {
            return $instance;
        }

        $closure = $this->registered->get($alias);
        if ($closure !== null) {
            $this->instances->set($alias, $closure($this));
        }
        return $this->instances->get($alias);
    }

    public function getNew(string $alias): ?mixed
    {
        if (!$this->registered->contains($alias)) {
            return null;
        }

        $closure = $this->registered->get($alias);
        return ($closure !== null) ? $closure($this) : null;
    }
}

このクラス自体は型チェッカーに合格しているようですが、Container::get()orを使用するContainer::getNew()と、戻り値が typemixedであるため、これらによって返されたオブジェクトに対してメソッドを実行しようとすると、このエラーがスローされます。

メンバー x にアクセスしようとしていますが、これはオブジェクトではなく、混合値です

混合では明らかに非オブジェクトが許可されるため、これが理にかなっていることがわかりました。そのため、そのようなコードを でラップする必要がありますが、これをis_object()行っても型チェッカーのエラーが抑制されないようです。タイプチェッカーが理解できる、何かがHackのオブジェクトであることを確認するより良い方法はありますか?

また、この IoC コンテナー クラスは混合型に大きく依存しているため、私には少し見苦しいです。実行時に戻り値がオブジェクトであることを確認する必要があるのも理想的ではありません。これを行うより良い方法はありますか?ミックスをインターフェイス(IContainableなど)に変更するというアイデアを試してみて、コンテナに格納したいクラスにこれを実装させましたが、タイプチェッカーは、IContainableインターフェイスにメソッドが含まれていないと不平を言いましたコンテナから返されたオブジェクトを呼び出そうとしていました(コードの同じポイントでエラーが発生しましたが、別の理由で)。おそらく、私はこのアプローチで成功に近かったのでしょうか?

助けてくれてありがとう。

4

2 に答える 2

10

タイプチェッカーが理解できる、何かがHackのオブジェクトであることを確認するより良い方法はありますか?

おそらく、 を介して特定のインスタンスを確認する必要がありますinstanceof。例: (警告、ブラウザに直接入力されたコード)

<?hh // strict

class C {
  public function f(): void {}
}

function f(): mixed {
  return new C();
}

function g(): void {
  $c = f();
  // $c->f() won't work out here, $c is mixed
  if ($c instanceof C) {
    $c->f(); // This works now
  }
}

また、不要なことにも注意してください。これは?mixed冗長です。使用するだけmixedです。(mixed は何でもよいので、null になることもあります。書き込み時にエラーを生成すること?mixedは、ある時点でやるべきことのリストに含まれています。:))

また、この IoC コンテナー クラスは混合型に大きく依存しているため、私には少し見苦しいです。

あなたの直感はここで良いです。Facebook では、何かを として型付けしたい場合のほとんどで、mixed1) より具体的な型を記述する必要があるか、2) コードの構造が非常に貧弱であり、構造化の方法を再考する必要があることを発見しました。それはより良いタイプです。

より具体的なタイプを使用する必要があるかもしれません。あなたが示すように、インターフェースを使用すると役立ちます。instanceof必要なことのほとんどが実際にはそのインターフェイスの一部であり、非常にまれに何か他のことをする必要があることが判明した場合は、上記の機能と組み合わせることができます。また、Genericsの使用方法を確認することもできますContainer。それぞれが異なる特定のサブクラスまたはインターフェースに対して何度もインスタンス化される場合Container、ジェネリックはおそらくあなたが望むものです。それがシングルトンの場合、おそらくそうではないかもしれません。(また、ここでは示していませんが、 が保持するクラスと何らかの形で相互作用する場合は、ジェネリックに対する制約Containerが必要になる場合があります。)

しかし、構造上の問題が原因でこの問題が発生していると思われます。これに出くわしたときに私が考えるいくつかのことを以下に示します: そもそもクラスのインスタンス化の周りに抽象化のこの層が必要なのはなぜですか? それはどのような機能を提供しているか、その機能を同種 (つまり、型付け可能) にすることができますか? ) 異種クラスのインスタンス化の問題とは別ですか? 少しの間、形式的な型を無視します (つまり、バニラ PHP でこれを書いていた場合)、使用するクラスはどのようにContainerそれが正しいことを知っていますか?何が非公式であるか、呼び出しコードに結び付けられているかに関係なく、何が行われるか、何が行われるかについてある程度の知識が必要です。そうでない場合、これはそもそも機能しません。その情報がどこでどのように体系化されているかを考えてから、それを明示する方法を見つけられるかどうかを検討してください。

お役に立てれば!何か明確にすることができる場合は、コメントでお知らせください。そしてもちろん、質問を続けてください。多くの FB Hack エンジニアや知識豊富なコミュニティ メンバーが「hacklang」タグを注意深く見ています :) (人々が Hack BTW を試していることに本当に興奮しています!それを楽しんでいます。)

于 2014-05-10T17:16:13.723 に答える
0

6 か月遅れていることはわかっていますが、この問題に対する解決策を提供したいと思います。

プロジェクトをスキャンしてファクトリ メソッドを探し、それらを 1 つのクラスにコンパイルするスクリプトを作成することで、この問題を回避しました。

これは、ファクトリのエイリアスとファクトリが生成するオブジェクトの型の完全な名前の 2 つの引数を取るユーザー定義プロパティ をスキャンすることで実現しました。providesまた、コンパイル スクリプトは、各ファクトリが 1 つのパラメーター (コンパイル済みのファクトリ クラス) のみを受け取るようにします。

本質的には、実行時にコンテナーにデータを入力するのではなく、コンパイル時にデータを入力します。コンテナー クラスのインスタンスがコンテナーではなく、コンテナー クラス定義がコンテナーです。

それはまだ進行中の作業ですが、 githubで私のソリューションを見ることができます

于 2014-12-08T07:56:23.407 に答える