89

たぶん私は何かを逃したかもしれませんが、関数が引数を持つか、ユーザーオブジェクトの配列などを返す必要があることを定義するオプションはありますか?

次のコードを検討してください。

<?php

class User
{
    protected $name;

    protected $age;

    /**
     * User constructor.
     *
     * @param $name
     */
    public function __construct(string $name, int $age)
    {
        $this->name = $name;
        $this->age = $age;
    }

    /**
     * @return mixed
     */
    public function getName() : string
    {
        return $this->name;
    }

    public function getAge() : int
    {
        return $this->age;
    }
}

function findUserByAge(int $age, array $users) : array
{
    $result = [];
    foreach ($users as $user) {
        if ($user->getAge() == $age) {
            if ($user->getName() == 'John') {
                // complicated code here
                $result[] = $user->getName(); // bug
            } else {
                $result[] = $user;
            }
        }
    }

    return $result;
}

$users = [
    new User('John', 15),
    new User('Daniel', 25),
    new User('Michael', 15),
];

$matches = findUserByAge(15, $users);

foreach ($matches as $user) {
    echo $user->getName() . ' '.$user->getAge() . "\n";
}

findUserByAge関数がユーザーの配列を返すように指示するPHP7のオプションはありますか? タイプヒンティングが追加されたときに可能になるはずですが、オブジェクトの配列のタイプヒンティングに関する情報が見つからないため、おそらくPHP 7には含まれていません。含まれていない場合、理由はありますか?タイプヒントが追加されたときに含まれていませんか?

4

7 に答える 7

133

含まれていません。

含まれていない場合、タイプヒントが追加されたときに含まれていなかった理由の手がかりはありますか?

現在の配列の実装では、配列自体に型情報が含まれていないため、実行時にすべての配列要素をチェックする必要があります。

実際には、PHP 5.6 向けに既に提案されていますが、却下されました: RFC "arrayof" - 興味深いことに、無視できることが判明したパフォーマンスの問題のためではなく、正確にどのように実装すべきかについて合意がなかったためです。スカラー型のヒントがないと不完全だという反論もありました。議論全体に興味がある場合は、メーリング リストのアーカイブ を読んでください。

IMHO 配列型ヒントは、型付き配列と一緒に使用することで最大のメリットが得られるので、ぜひ実装してもらいたいと思っています。

そろそろ新しい RFC を作成し、この議論を再開する時期に来ているのかもしれません。


部分的な回避策:

ヒントの可変引数を入力して、署名を次のように書くことができます

function findUserByAge(int $age, User ...$users) : array

使用法:

findUserByAge(15, ...$userInput);

この呼び出しでは、引数$userInputは単一の変数に「アンパック」され、メソッド自体では配列に「パック」され$usersます。各項目はタイプであることが検証されますUser$userInputイテレータにすることもできます。配列に変換されます。

残念ながら、戻り値の型に対する同様の回避策はなく、最後の引数に対してのみ使用できます。

于 2015-12-14T18:11:56.040 に答える
8

一般的な配列の型ヒントについて一般的な回答をしています。

選択した回答のバリエーションを作成しました。主な違いは、パラメータがチェックされたクラスの多くのインスタンスではなく配列であることです。

/**
 * @param $_foos Foo[]
 */
function doFoo(array $_foos)
{return (function(Foo ...$_foos){

    // Do whatever you want with the $_foos array

})(...$_foos);}

少し曖昧に見えますが、理解するのはとても簡単です。呼び出しごとに手動で配列を常にアンパックする代わりに、関数内のクロージャーは、パラメーターとしてアンパックされた配列で呼び出されます。

function doFoo(array $_foos)
{
    return (function(Foo ...$_foos){ // Closure

    // Do whatever you want with the $_foos array

    })(...$_foos); //Main function's parameter $_foos unpacked
}

ArrayOfType パラメーターを持つ他の言語関数と同じように関数を使用できるため、これはかなりクールだと思います。さらに、エラーは、残りの PHP 型ヒント エラーと同じ方法で処理されます。さらに、あなたの関数を使用する他のプログラマーを混乱させず、配列をアンパックする必要があります。

これがどのように機能するかを理解するには、プログラミングの経験が少し必要です。複数のパラメーターが必要な場合は、クロージャーの「use」セクションにいつでも追加できます。

doc コメントを使用して型ヒントを公開することもできます。

/**
 * @param $_foos Foo[] <- An array of type Foo
 */

OO の例を次に示します。

class Foo{}

class NotFoo{}

class Bar{
    /**
     * @param $_foos Foo[]
     */
    public function doFoo(array $_foos, $_param2)
    {return (function(Foo ...$_foos) use($_param2){

        return $_param2;

    })(...$_foos);}
}

$myBar = new Bar();
$arrayOfFoo = array(new Foo(), new Foo(), new Foo());
$notArrayOfFoo = array(new Foo(), new NotFoo(), new Foo());

echo $myBar->doFoo($arrayOfFoo, 'Success');
// Success

echo $myBar->doFoo($notArrayOfFoo, 'Success');
// Uncaught TypeError: Argument 2 passed to Bar::{closure}() must be an instance of Foo, instance of NotFoo given...

注: これは、オブジェクト以外の型 (int、string など) でも機能します。

于 2019-01-23T18:11:56.457 に答える