443

したがって、PHPDocでは、@varメンバー変数宣言の上にその型を示唆するように指定できます。次に、IDE、たとえば。PHPEdは、処理しているオブジェクトのタイプを認識し、その変数のコードインサイトを提供できるようになります。

<?php
  class Test
  {
    /** @var SomeObj */
    private $someObjInstance;
  }
?>

これは、後でそれらのオブジェクトを反復処理するときに適切なヒントを取得できるように、オブジェクトの配列に対して同じことを行う必要があるまではうまく機能します。

それで、メンバー変数がSomeObjsの配列であることを指定するためにPHPDocタグを宣言する方法はありますか?@varたとえば、配列は十分ではなく、@var array(SomeObj)有効ではないようです。

4

14 に答える 14

919

JetBrains の PhpStorm IDE では、次のように使用できます/** @var SomeObj[] */

/**
 * @return SomeObj[]
 */
function getSomeObjects() {...}

phpdoc のドキュメントでは、次の方法を推奨しています。

単一の型を含むように指定されている場合、Type 定義はリーダーに各配列要素の型を通知します。その場合、特定の配列の要素として 1 つの Type のみが期待されます。

例:@return int[]

于 2009-11-19T13:50:37.600 に答える
60

Netbeans のヒント:

User クラスの配列$users[0]->に対してコード補完を取得します。$this->

/**
 * @var User[]
 */
var $users = array();

の補完を行うと、クラスメンバーのリストで配列のタイプを確認することもできます$this->...

于 2015-05-02T06:38:31.057 に答える
32

変数がオブジェクトの配列であることを指定するには:

$needles = getAllNeedles();
/* @var $needles Needle[] */
$needles[1]->...                        //codehinting works

これはNetbeans 7.2で機能します(私はそれを使用しています)

以下にも対応:

$needles = getAllNeedles();
/* @var $needles Needle[] */
foreach ($needles as $needle) {
    $needle->...                        //codehinting works
}

したがって、 内で宣言を使用するforeach必要はありません。

于 2013-01-01T13:16:13.470 に答える
32

PSR-5: PHPDocはジェネリック スタイルの表記法を提案しています。

構文

Type[]
Type<Type>
Type<Type[, Type]...>
Type<Type[|Type]...>

コレクション内の値は、別の配列や別のコレクションであっても構いません。

Type<Type<Type>>
Type<Type<Type[, Type]...>>
Type<Type<Type[|Type]...>>

<?php

$x = [new Name()];
/* @var $x Name[] */

$y = new Collection([new Name()]);
/* @var $y Collection<Name> */

$a = new Collection(); 
$a[] = new Model_User(); 
$a->resetChanges(); 
$a[0]->name = "George"; 
$a->echoChanges();
/* @var $a Collection<Model_User> */

注: IDE がコード支援を行うことを期待している場合、IDE が PHPDoc ジェネリック スタイルのコレクション表記をサポートしているかどうかは別の問題です。

この質問に対する私の答えから。

于 2016-09-09T00:02:44.453 に答える
11

Robert C. Martin による「Clean Code」で概説されているように、私はクリーンなコードを読み書きすることを好みます。彼の信条に従う場合、(API のユーザーとして) 開発者に配列の (内部) 構造を知ってもらう必要はありません。

API ユーザーは、次のように質問する場合があります。これは 1 次元のみの配列ですか? オブジェクトは多次元配列のすべてのレベルに分散していますか? すべてのオブジェクトにアクセスするには、ネストされたループ (foreach など) がいくつ必要ですか? その配列に「格納」されるオブジェクトのタイプは何ですか?

概説したように、その配列 (オブジェクトを含む) を 1 次元配列として使用したいと考えています。

西が概説したように、次を使用できます。

/**
 * @return SomeObj[]
 */

そのために。

ただし、注意してください - これは標準の docblock 表記法ではありません。この表記法は、一部の IDE プロデューサーによって導入されました。

わかりました、わかりました、開発者として、「[]」が PHP の配列に関連付けられていることを知っています。しかし、通常の PHP コンテキストでは、「something[]」は何を意味するのでしょうか? 「[]」は、「何か」内に新しい要素を作成することを意味します。新しい要素はすべてである可能性があります。しかし、表現したいのは、同じタイプのオブジェクトの配列であり、正確なタイプです。ご覧のとおり、IDE プロデューサーは新しいコンテキストを導入します。あなたが学ばなければならなかった新しい文脈。他の PHP 開発者が (ドキュメントブロックを理解するために) 学ばなければならない新しいコンテキスト。スタイルが悪い(!)。

配列には 1 つの次元があるため、その「オブジェクトの配列」を「リスト」と呼びたいと思うかもしれません。「リスト」は、他のプログラミング言語では非常に特別な意味を持つことに注意してください。たとえば、「コレクション」と呼ぶ方がはるかに適切です。

覚えておいてください: OOP のすべてのオプションを有効にするプログラミング言語を使用します。配列の代わりにクラスを使用し、クラスを配列のように走査可能にします。例えば:

class orderCollection implements ArrayIterator

または、多次元配列/オブジェクト構造内の異なるレベルに内部オブジェクトを格納する場合:

class orderCollection implements RecursiveArrayIterator

このソリューションは、配列を「orderCollection」型のオブジェクトに置き換えますが、これまでのところ、IDE 内でコード補完を有効にしないでください。わかった。次のステップ:

docblocks とのインターフェースによって導入されるメソッドを実装します - 特に:

/**
 * [...]
 * @return Order
 */
orderCollection::current()

/**
 * [...]
 * @return integer E.g. database identifier of the order
 */
orderCollection::key()

/**
 * [...]
 * @return Order
 */
orderCollection::offsetGet()

以下に対して型ヒントを使用することを忘れないでください。

orderCollection::append(Order $order)
orderCollection::offsetSet(Order $order)

このソリューションは、多くの導入を停止します:

/** @var $key ... */
/** @var $value ... */

Zahymakaが彼女/彼の答えで確認したように、コードファイル全体(ループ内など)。API ユーザーは、コード補完のためにその docblock を導入する必要はありません。@return を 1 か所だけにすると、冗長性 (@var) が可能な限り削減されます。「docBlocks with @var」を振りかけると、コードが読みにくくなります。

最後に、完了です。達成するのは難しいように見えますか?大ハンマーでナッツを割るように見えますか?あなたはそのインターフェースときれいなコードに精通しているので、そうではありません。覚えておいてください:あなたのソースコードは一度書かれ、何度も読まれます.

IDE のコード補完がこのアプローチで機能しない場合は、より良いもの (IntelliJ IDEA、PhpStorm、Netbeans など) に切り替えるか、IDE プロデューサーの問題トラッカーに機能リクエストを提出してください。

私のトレーナーであり、素晴らしいことを教えてくれた Christian Weiss (ドイツ出身) に感謝します。PS: XING で私と彼に会いましょう。

于 2012-10-16T23:32:54.327 に答える
5

NetBeans 7.0では(これよりも低い場合もあります)、戻り型「テキストオブジェクトを含む配列」を宣言することができます。@return Textコードヒントは次のように機能します。

編集: @BobFangerの提案で例を更新しました

/**
 * get all Tests
 *
 * @return Test|Array $tests
 */
public function getAllTexts(){
    return array(new Test(), new Test());
}

そしてそれを使用するだけです:

$tests =  $controller->getAllTests();
//$tests->         //codehinting works!
//$tests[0]->      //codehinting works!

foreach($tests as $text){
    //$test->      //codehinting works!
}

完璧ではありませんが、「混合」したままにしておくと、価値がなくなります。

短所は、エラーをスローするテキストオブジェクトとして配列を読み取ることが許可されていることです。

于 2013-02-06T14:01:12.103 に答える
5

DanielaWaranie が彼女の回答で述べたように、$collectionObject で $items を反復処理するときに $item のタイプを指定する方法があります。値を返すメソッドと残りのメソッドに追加@return MyEntitiesClassNameします。current()IteratorArrayAccess

ブーム!/** @var SomeObj[] $collectionObj */overの必要はforeachなく、コレクション オブジェクトで正しく動作し、 として記述された特定のメソッドでコレクションを返す必要はありません@return SomeObj[]

すべての IDE がサポートしているわけではないと思いますが、PhpStorm では問題なく動作するので、満足しています。

例:

class MyCollection implements Countable, Iterator, ArrayAccess {

    /**
     * @return User
     */
    public function current() {
        return $this->items[$this->cursor];
    }

    //... implement rest of the required `interface` methods and your custom
}

この回答を投稿すると、どのような有用な情報が追加されますか

私の場合current()、残りのinterface-methods はAbstract-collection クラスに実装されており、最終的にコレクションに格納されるエンティティの種類はわかりません。

@methodトリックは次のとおりです。抽象クラスで戻り値の型を指定しないでください。代わりに、特定のコレクション クラスの説明でPhpDoc 命令を使用します。

例:

class User {

    function printLogin() {
        echo $this->login;
    }

}

abstract class MyCollection implements Countable, Iterator, ArrayAccess {

    protected $items = [];

    public function current() {
        return $this->items[$this->cursor];
    }

    //... implement rest of the required `interface` methods and your custom
    //... abstract methods which will be shared among child-classes
}

/**
 * @method User current()
 * ...rest of methods (for ArrayAccess) if needed
 */
class UserCollection extends MyCollection {

    function add(User $user) {
        $this->items[] = $user;
    }

    // User collection specific methods...

}

さて、クラスの使用法:

$collection = new UserCollection();
$collection->add(new User(1));
$collection->add(new User(2));
$collection->add(new User(3));

foreach ($collection as $user) {
    // IDE should `recognize` method `printLogin()` here!
    $user->printLogin();
}

繰り返しますが、すべての IDE がサポートしているわけではないと思いますが、PhpStorm はサポートしています。試してみて、結果をコメントに投稿してください!

于 2014-10-30T03:56:29.610 に答える
5

array[type]Zend Studio で使用します。

Zend Studio で、またはarray[MyClass]うまく機能します。array[int]array[array[MyClass]]

于 2014-04-14T23:18:31.977 に答える
3

パーティーに遅れていることはわかっていますが、最近この問題に取り組んでいます。受け入れられた答えは正しいですが、これが最善の方法ではないため、誰かがこれを見てくれることを願っています。少なくとも PHPStorm ではありませんが、NetBeans はテストしていません。

最善の方法は、ネイティブの配列型を使用するのではなく、ArrayIterator クラスを拡張することです。これにより、インスタンス レベルではなくクラス レベルでヒントを入力できます。つまり、コード全体ではなく、PHPDoc を 1 回だけ使用する必要があります (これは面倒で DRY に違反するだけでなく、問題になる可能性もあります)。リファクタリング - PHPStorm には、リファクタリング時に PHPDoc が欠落する傾向があります)

以下のコードを参照してください。

class MyObj
{
    private $val;
    public function __construct($val) { $this->val = $val; }
    public function getter() { return $this->val; }
}

/**
 * @method MyObj current()
 */
class MyObjCollection extends ArrayIterator
{
    public function __construct(Array $array = [])
    {
        foreach($array as $object)
        {
            if(!is_a($object, MyObj::class))
            {
                throw new Exception('Invalid object passed to ' . __METHOD__ . ', expected type ' . MyObj::class);
            }
        }
        parent::__construct($array);
    }

    public function echoContents()
    {
        foreach($this as $key => $myObj)
        {
            echo $key . ': ' . $myObj->getter() . '<br>';
        }
    }
}

$myObjCollection = new MyObjCollection([
    new MyObj(1),
    new MyObj('foo'),
    new MyObj('blah'),
    new MyObj(23),
    new MyObj(array())
]);

$myObjCollection->echoContents();

ここで重要なのは、ArrayIterator@method MyObj current()から継承された戻り値の型 (つまりmixed) をオーバーライドする PHPDoc です。この PHPDoc が含まれているということは、 を使用してクラス プロパティを反復処理するforeach($this as $myObj)と、変数を参照するときにコード補完が得られることを意味します。$myObj->...

コード全体に散在するクラスのインスタンスではなく、反復可能なクラスで反復子型を宣言しているため、これはこれを実現するための最も適切な方法です (少なくとも PHP が型付き配列を導入するまでは)。

ここでは ArrayIterator を拡張するための完全なソリューションを示していないため、この手法を使用する場合は、次のことも行うことができます。

  • offsetGet($index)やなどのメソッドのために、必要に応じて他のクラスレベルの PHPDoc を含めます。next()
  • サニティ チェックis_a($object, MyObj::class)をコンストラクタからプライベート メソッドに移動する
  • offsetSet($index, $newval)および_append($value)
于 2016-12-23T00:21:18.220 に答える
2

問題は@var、単一の型を表すことができるだけであり、複雑な式を含まないことです。「Foo の配列」の構文がある場合、そこでやめて、「2 つの Foo と 3 つの Bar を含む配列の配列」の構文を追加しないのはなぜですか? 要素のリストはおそらくそれよりも一般的であることは理解していますが、それは滑りやすい斜面です。

個人的には、@var Foo[]「Foo の配列」を表すのに使用したことがありますが、IDE ではサポートされていません。

于 2009-04-22T21:04:10.787 に答える
1
<?php foreach($this->models as /** @var Model_Object_WheelModel */ $model): ?>
    <?php
    // Type hinting now works:
    $model->getImage();
    ?>
<?php endforeach; ?>
于 2010-06-27T21:29:11.443 に答える
-5

機能しているものを見つけました。命を救うことができます!

private $userList = array();
$userList = User::fetchAll(); // now $userList is an array of User objects
foreach ($userList as $user) {
   $user instanceof User;
   echo $user->getName();
}
于 2010-01-13T10:43:15.870 に答える