460 Stimmen

PHPDoc type hinting für Array von Objekten?

In PHPDoc kann man also angeben @var über der Deklaration der Mitgliedsvariablen, um einen Hinweis auf ihren Typ zu geben. Dann weiß eine IDE, z.B.. PHPEd, wissen, mit welchem Objekttyp sie arbeiten und können einen Einblick in den Code dieser Variablen geben.

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

Dies funktioniert gut, bis ich dasselbe mit einem Array von Objekten tun muss, um einen richtigen Hinweis zu erhalten, wenn ich später durch diese Objekte iteriere.

Gibt es also eine Möglichkeit, ein PHPDoc-Tag zu deklarieren, um anzugeben, dass die Mitgliedsvariable ein Array aus SomeObj s? @var Array ist nicht ausreichend, und @var array(SomeObj) scheint zum Beispiel nicht gültig zu sein.

11voto

DanielaWaranie Punkte 1405

Ich ziehe es vor, sauberen Code zu lesen und zu schreiben - wie in "Clean Code" von Robert C. Martin beschrieben. Wenn Sie seinem Credo folgen, sollten Sie nicht verlangen, dass der Entwickler (als Benutzer Ihrer API) die (interne) Struktur Ihres Arrays kennt.

Der API-Benutzer könnte sich fragen: Ist das ein Array mit nur einer Dimension? Sind die Objekte auf allen Ebenen eines mehrdimensionalen Arrays verteilt? Wie viele verschachtelte Schleifen (foreach usw.) brauche ich, um auf alle Objekte zuzugreifen? Welche Art von Objekten wird in diesem Array "gespeichert"?

Wie Sie dargelegt haben, möchten Sie dieses Array (das Objekte enthält) als eindimensionales Array verwenden.

Wie von Nishi skizziert, können Sie verwenden:

/**
 * @return SomeObj[]
 */

dafür.

Aber noch einmal: Seien Sie sich bewusst, dass dies keine Standard-Docblock-Notation ist. Diese Notation wurde von einigen IDE-Herstellern eingeführt.

Okay, okay, als Entwickler wissen Sie, dass "[]" in PHP an ein Array gebunden ist. Aber was bedeutet "irgendwas[]" im normalen PHP-Kontext? "[]" bedeutet: ein neues Element innerhalb von "irgendwas" erstellen. Das neue Element könnte alles sein. Was Sie aber ausdrücken wollen, ist: Array von Objekten mit demselben Typ und seinem genauen Typ. Wie Sie sehen können, führt der IDE-Produzent einen neuen Kontext ein. Einen neuen Kontext, den Sie lernen müssen. Einen neuen Kontext, den andere PHP-Entwickler lernen mussten (um Ihre Docblocks zu verstehen). Schlechter Stil (!).

Da Ihr Array eine Dimension hat, möchten Sie dieses "Array von Objekten" vielleicht als "Liste" bezeichnen. Seien Sie sich bewusst, dass "Liste" in anderen Programmiersprachen eine sehr spezielle Bedeutung hat. Es wäre zum Beispiel viel besser, es "Sammlung" zu nennen.

Denken Sie daran: Sie verwenden eine Programmiersprache, die Ihnen alle Möglichkeiten der OOP bietet. Verwenden Sie eine Klasse anstelle eines Arrays und machen Sie Ihre Klasse wie ein Array durchsuchbar. Z.B.:

class orderCollection implements ArrayIterator

Oder wenn Sie die internen Objekte auf verschiedenen Ebenen innerhalb einer mehrdimensionalen Array-/Objektstruktur speichern möchten:

class orderCollection implements RecursiveArrayIterator

Diese Lösung ersetzt Ihr Array durch ein Objekt vom Typ "orderCollection", aber aktivieren Sie die Code-Vervollständigung in Ihrer IDE noch nicht. Nun gut. Nächster Schritt:

Implementieren Sie die Methoden, die durch die Schnittstelle mit Docblocks eingeführt werden - insbesondere:

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

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

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

Vergessen Sie nicht, Type Hinting für zu verwenden:

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

Diese Lösung verhindert die Einführung einer Menge von:

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

überall in Ihren Codedateien (z. B. in Schleifen), wie Zahymaka in ihrer Antwort bestätigt hat. Ihr API-Benutzer ist nicht gezwungen, diese docblocks einzuführen, um Code-Vervollständigung zu haben. Mit @return an nur einer Stelle wird die Redundanz (@var) so weit wie möglich reduziert. Das Einstreuen von "docBlocks mit @var" würde Ihren Code schlecht lesbar machen.

Endlich sind Sie fertig. Sieht schwer zu erreichen aus? Sieht es so aus, als würde man mit einem Vorschlaghammer eine Nuss knacken? Nicht wirklich, denn Sie sind mit diesen Schnittstellen und sauberem Code vertraut. Denken Sie daran: Ihr Quellcode wird einmal geschrieben/viel gelesen.

Wenn die Code-Vervollständigung Ihrer IDE mit diesem Ansatz nicht funktioniert, wechseln Sie zu einer besseren IDE (z.B. IntelliJ IDEA, PhpStorm, Netbeans) oder stellen Sie einen Feature-Request im Issue-Tracker Ihres IDE-Herstellers.

Danke an Christian Weiss (aus Deutschland), dass er mein Trainer war und mir so tolle Sachen beigebracht hat. PS: Triff mich und ihn auf XING.

10voto

Max Punkte 544

Wenn Sie PHPStorm 2021.2+ verwenden, können Sie auch diese Syntax verwenden (Array shapes):

@property array{name: string, content: string}[] $files

ou

@var array{name: string, content: string}[] $files

6voto

d.raev Punkte 8510

In NetBeans 7.0 (möglicherweise auch niedriger) können Sie den Rückgabetyp "Array mit Textobjekten" wie folgt deklarieren @return Text und der Codehinweis wird funktionieren:

Editar: das Beispiel mit dem Vorschlag von @Bob Fanger aktualisiert

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

und verwenden Sie es einfach:

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

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

Es ist nicht perfekt, aber es ist besser, als es einfach nur "gemischt" zu lassen, was keinen Wert hat.

CONS ist Sie sind erlaubt, das Array als Text-Objekt, die Fehler werfen wird.

5voto

Erick Robertson Punkte 30890

Utilice array[type] in Zend Studio.

In Zend Studio, array[MyClass] o array[int] oder sogar array[array[MyClass]] funktionieren großartig.

5voto

Pavel Punkte 3627

Wie DanielaWaranie in ihrer Antwort erwähnt - es gibt eine Möglichkeit, den Typ von $item anzugeben, wenn Sie über $items in $collectionObject iterieren: hinzufügen. @return MyEntitiesClassName à current() und der Rest der Iterator y ArrayAccess -Methoden, die Werte zurückgeben.

Bumm! Kein Bedarf an /** @var SomeObj[] $collectionObj */ über foreach und funktioniert direkt mit dem Sammlungsobjekt, ohne dass die Sammlung mit einer speziellen Methode zurückgegeben werden muss, die als @return SomeObj[] .

Ich vermute, dass nicht alle IDEs es unterstützen, aber es funktioniert perfekt in PhpStorm, was mich glücklicher macht.

Exemple :

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
}

Was ich noch hinzufügen wollte, um diese Antwort zu posten

In meinem Fall current() und Rest von interface -Methoden sind implementiert in Abstract -Sammlungsklasse und ich weiß nicht, welche Art von Entitäten schließlich in der Sammlung gespeichert werden.

Hier ist also der Trick: Geben Sie den Rückgabetyp nicht in der abstrakten Klasse an, sondern verwenden Sie die PhpDoc-Instruktion @method in der Beschreibung einer bestimmten Sammelklasse.

Exemple :

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...

}

Nun zur Verwendung der Klassen:

$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();
}

Noch einmal: Ich vermute, dass nicht alle IDEs dies unterstützen, aber PhpStorm schon. Versuchen Sie Ihre, posten Sie in Kommentar die Ergebnisse!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X