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.

3voto

e_i_pi Punkte 4261

Ich weiß, ich bin spät dran, aber ich habe mich in letzter Zeit mit diesem Problem beschäftigt. Ich hoffe, jemand sieht dies, denn die akzeptierte Antwort, obwohl korrekt, ist nicht die beste Art und Weise, wie Sie dies tun können. Zumindest nicht in PHPStorm, NetBeans habe ich allerdings nicht getestet.

Am besten ist es, die Klasse ArrayIterator zu erweitern, anstatt native Array-Typen zu verwenden. Dies ermöglicht es Ihnen, Hinweise auf Klassenebene und nicht auf Instanzebene zu geben, was bedeutet, dass Sie PHPDoc nur einmal und nicht im gesamten Code verwenden müssen (was nicht nur unordentlich ist und gegen DRY verstößt, sondern auch problematisch sein kann, wenn es um Refactoring geht - PHPStorm hat die Angewohnheit, PHPDoc beim Refactoring zu übersehen)

Siehe Code unten:

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

Der Schlüssel dazu ist die PHPDoc @method MyObj current() Überschreibung des von ArrayIterator geerbten Rückgabetyps (der mixed ). Die Einbeziehung dieses PHPDoc bedeutet, dass wir bei der Iteration über die Klasseneigenschaften mit foreach($this as $myObj) erhalten wir die Code-Vervollständigung, wenn wir uns auf die Variable $myObj->...

Für mich ist dies der sauberste Weg, um dies zu erreichen (zumindest bis PHP Typed Arrays einführt, falls dies jemals der Fall sein wird), da wir den Iterator-Typ in der Iterable-Klasse deklarieren und nicht in Instanzen der Klasse, die im Code verstreut sind.

Ich habe hier nicht die vollständige Lösung für die Erweiterung von ArrayIterator gezeigt, wenn Sie also diese Technik verwenden, möchten Sie das vielleicht auch:

  • Fügen Sie bei Bedarf weitere PHPDoc auf Klassenebene ein, z. B. für Methoden wie offsetGet($index) y next()
  • Verschieben Sie die Plausibilitätsprüfung is_a($object, MyObj::class) aus dem Konstruktor in eine private Methode
  • Rufen Sie diese (jetzt private) Sicherheitsüberprüfung von Methodenüberschreibungen wie offsetSet($index, $newval) y append($value)

2voto

troelskn Punkte 110542

Das Problem ist, dass @var kann nur einen einzigen Typ bezeichnen - und nicht eine komplexe Formel enthalten. Wenn man eine Syntax für "array of Foo" hat, warum sollte man dort aufhören und nicht eine Syntax für "array of array, that contains 2 Foo's and three Bar's" hinzufügen? Ich verstehe, dass eine Liste von Elementen vielleicht allgemeiner ist als das, aber es ist eine schlüpfrige Angelegenheit.

Persönlich habe ich einige Male die @var Foo[] um "ein Array von Foo's" zu bezeichnen, aber es wird von IDE's nicht unterstützt.

2voto

Scott Hovestadt Punkte 59
<?php foreach($this->models as /** @var Model_Object_WheelModel */ $model): ?>
    <?php
    // Type hinting now works:
    $model->getImage();
    ?>
<?php endforeach; ?>

-5voto

eupho Punkte 23

Ich habe etwas gefunden, das funktioniert, es kann Leben retten!

private $userList = array();
$userList = User::fetchAll(); // now $userList is an array of User objects
foreach ($userList as $user) {
   $user instanceof User;
   echo $user->getName();
}

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