php - 配列にオブジェクトを格納 - 型のヒント-オブジェクトの配列を指定する



配列 取得 (4)

引数の型を配列として指定するにはどうすればよいですか? 「Foo」という名前のクラスがあるとします。

class Foo {}

そのクラスの型を引数として受け入れる関数があります:

function getFoo(Foo $f) {}

私が「Foo's」の配列を渡すと、私はエラーを出します。

キャッチ可能な致命的なエラー :getFoo()に渡された引数1はFooのインスタンスでなければならない

この問題を克服する方法はありますか? 多分何かのような

function getFoo(Foo $f[]) {}

https://code.i-harness.com


"Fooの配列"で作業していて、メソッドが "Fooの配列"を受け取るようにするには、次のようにします。

class ArrayOfFoo extends \ArrayObject {
    public function offsetSet($key, $val) {
        if ($val instanceof Foo) {
            return parent::offsetSet($key, $val);
        }
        throw new \InvalidArgumentException('Value must be a Foo');
    }
}

次に:

function workWithFoo(ArrayOfFoo $foos) {
    foreach ($foos as $foo) {
        // etc.
    }
}

$foos = new ArrayOfFoos();
$foos[] = new Foo();
workWithFoo($foos);

秘密のソースは、「配列のfoo」の新しい「型」を定義し、型ヒンティング保護を使用してその型を渡すことです。

Halaleneライブラリは、自分自身をロールしたくない場合、メンバーシップ要件チェック用の定型文を処理します。

class ArrayOfFoo extends \Haldayne\Boost\MapOfObjects {
    protected function allowed($value) { return $value instanceof Foo; }
}

(完全開示、私はHaldayneの著者です。)

ヒストリカルノート: RFC配列は、2014年にこの機能を提案しました。RFCは4日と16日で減少しました。 この概念は最近、内部のリストに再び現れましたが、苦情は元のRFCに対して徴収されたものとほとんど同じです:このチェックを加えることは、 パフォーマンスに大きな影響を与えます


古い投稿ですが、PHP7では、型付きの配列ヒントを実現するために、いくつかの制限がありますが、可変の関数と配列のアンパックを使用することができます。 (私は以前のバージョンではテストしなかった)。

例:

class Foo {
  public function test(){
    echo "foo";
  }   
};  

class Bar extends Foo {
  //override parent method
  public function test(){
    echo "bar";
  }   
}          

function test(Foo ...$params){
  foreach($params as $param){
    $param->test();
  }   
}   

$f = new Foo();
$b = new Bar();

$arrayOfFoo = [$f,$b];

test(...$arrayOfFoo);
//will output "foobar"


制限事項:

  1. これは、実際に型付き配列を渡すわけではないので、技術的には解決策ではありません。 その代わりに、配列のアンパック演算子1 (関数呼び出しでは "...")を使用して、配列をパラメータのリストに変換します。各パラメータはバリデーション宣言2でヒンティングされた型でなければなりません(省略記号)。

  2. 関数呼び出しの "..."は絶対必要です(これは驚くべきことではありません)。 電話しようとしています

    test($arrayOfFoo)

    コンパイラは配列ではなくfooのパラメータを期待しているので、上記の例では型エラーが発生します。 いくつかの型ヒントを保持しながら、与えられた型の配列を直接渡すための、ハッキリではあるが解決策は以下を参照してください。

  3. Variadic関数は1つの可変パラメータを持つことができ、最後のパラメータでなければなりません(そうでなければ、可変引数がどこで終了し、次のパラメータが始まるかをコンパイラが決定するので)

    function test(Foo ...$foos, Bar ...$bars){ 
        //...
    }

    または

    function test(Foo ...$foos, Bar $bar){
        //...
    }


僅かに良い - ちょうどチェック - 各要素の代替:

次の手順 、(1)関数本体で使用されるパラメータが型チェックで関数を乱雑にすることなく正しい型であることを保証し、(2)通常の型例外をスローする。

検討してください:

function alt(Array $foos){
    return (function(Foo ...$fooParams){

        //treat as regular function body

        foreach($fooParams as $foo){
            $foo->test();
        }

    })(...$foos);
}

このアイデアは、すぐに呼び出された閉鎖の結果を定義して返します。これは、すべてのバリデーショナル/アンパックビジネスを処理します。 (原則をさらに拡張して、この構造の関数を生成して定型文を減らす高階関数を定義することもできます)。 上記の例では、

alt($arrayOfFoo) // also outputs "foobar"

このアプローチの問題点は次のとおりです。

(1)経験の浅い開発者にとっては、特に不明な点があります。

(2)パフォーマンス上のオーバーヘッドが発生する可能性があります。

(3)配列要素を内部的にチェックするのと同じように、関数型宣言を検査しなければならないか(型の例外を享受する)、型指定された配列だけが有効なパラメータであることを認識しなければならない。 インタフェースまたは抽象関数では、フルタイプのヒントをエンコードできませんでした。 上記のソート(または類似のもの)の実装が期待されているとコメントするだけです。


ノート

[1]。 一言で言えば、配列アンパックは同等のものをレンダリングする

example_function($a,$b,$c);

そして

example_function(...[$a,$b,$c]);


[2]。 一言で言えば、フォームの多様な関数

function example_function(Foo ...$bar){
    //...
}

次のいずれかの方法で有効に呼び出すことができます。

example_function();
example_function(new Foo());
example_function(new Foo(), new Foo());
example_function(new Foo(), new Foo(), new Foo());
//and so on

class Foo {
/**
 * @param Foo[] $f
 */
    function getFoo($f) {

    }
}

function getFoo()

一般的に、あなたはFooヒントを与えるaddメソッドを持っています

function addFoo( Foo $f )

したがって、getterはFooの配列を返し、addメソッドはFooの配列を確実に確保できます。

EDIT getterから引数を削除しました。 私が何を考えているのか分からず、ゲッターで議論する必要はありません。

完全なクラスの例を表示するにはちょうど編集

class FooBar
{
    /**
     * @return array
     */
    private $foo;

    public function getFoo()
    {
        return $foo;
    }

    public function setFoo( array $f )
    {
        $this->foo = $f;

        return $this;
    }

    public function addFoo( Foo $f )
    {
        $this->foo[] = $f;

        return $this;
    }
}

あなたは$fooFooの配列であることを保証するためのaddメソッドを持っているので、一般的に、おそらくはsetterメソッドを持つべきではありませんが、クラス内で何が起こっているかを示すのに役立ちます。





type-hinting