PHPDoc Typ hinting dla tablicy obiektów?

Tak więc, w PHPDoc można określić @var nad deklaracją zmiennej członkowskiej, aby wskazać jej typ. Potem IDE, dla ex. PHPEd, będzie wiedział, z jakim typem obiektu pracuje i będzie w stanie dostarczyć wgląd w kod tej zmiennej.

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

To działa świetnie, dopóki nie muszę zrobić tego samego z tablicą obiektów, aby móc uzyskać właściwą podpowiedź, gdy później przejrzę te obiekty.

Więc, czy istnieje sposób zadeklarowania znacznika PHPDoc, aby określić, że zmienna członkowska czy tablica SomeObj s? @var tablica nie jest wystarczająca i @var array(SomeObj) nie wydaje się być poprawna, na przykład.

Author: Artem Russakovskii, 2009-04-22

13 answers

Najlepsze, co możesz zrobić, to powiedzieć:

foreach ($Objs as $Obj)
{
    /* @var $Obj Test */
    // You should be able to get hinting after the preceding line if you type $Obj->
}
Często to robię w Zend Studio. Nie wiem jak inni redaktorzy, ale powinno zadziałać.
 273
Author: Zahymaka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-28 11:40:19

W PhpStorm IDE z JetBrains możesz użyć /** @var SomeObj[] */, np.:

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

Dokumentacja phpdoc poleca tę metodę:

Określona zawierająca pojedynczy typ, definicja typu informuje czytelnika o typie każdego elementu tablicy. Tylko jeden typ jest wtedy oczekiwany jako element dla danej tablicy.

Przykład: @return int[]

 863
Author: Nishi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-24 06:53:35

NetBeans podpowiedzi:

Otrzymujesz zakończenie kodu na $users[0]-> i dla {[2] } dla tablicy klas użytkowników.

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

Możesz również zobaczyć typ tablicy na liście członków klasy po wykonaniu $this->...

 55
Author: user1491819,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-02 11:47:23

Aby określić zmienną jest tablica obiektów:

$needles = getAllNeedles();
/* @var $needles Needle[] */
$needles[1]->...                        //codehinting works
To działa w Netbeans 7.2 (używam go)

Działa również z:

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

Dlatego stosowanie deklaracji wewnątrz foreach nie jest konieczne.

 29
Author: Highmastdon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-01 13:16:13

PSR-5: PHPDoc proponuje formę notacji generycznej.

Składnia

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

Wartości w kolekcji mogą być nawet inną tablicą, a nawet inną kolekcją.

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

Przykłady

<?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> */

Uwaga: jeśli oczekujesz, że IDE pomoże Ci w kodowaniu, to kolejne pytanie dotyczy tego, czy IDE obsługuje notację kolekcji w stylu generycznym PHPDoc.

Z mojej odpowiedzi na to pytanie .

 19
Author: Gerard Roche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:07

Wolę czytać i pisać czysty kod - jak opisano w" Clean Code " Roberta C. Martina. Podążając za jego credo nie powinieneś wymagać od programisty (jako użytkownika Twojego API) znajomości (wewnętrznej) struktury tablicy.

Użytkownik API może zapytać: czy tablica ma tylko jeden wymiar? Czy obiekty są rozmieszczone na wszystkich poziomach wielowymiarowej tablicy? Ile zagnieżdżonych pętli (foreach, itp.) Czy muszę uzyskać dostęp do wszystkich obiektów? Jakiego typu obiekty są "przechowywane" w tym / align = "left" /

Jak już opisałeś, chcesz użyć tablicy (która zawiera obiekty) jako tablicy jednowymiarowej.

Zgodnie z opisem Nishi możesz użyć:

/**
 * @return SomeObj[]
 */
Za to.

Ale jeszcze raz: bądźcie świadomi - to nie jest standardowa notacja docblock. Ta notacja została wprowadzona przez niektórych producentów IDE.

Okay, okay, jako programista wiesz, że "[] " jest powiązane z tablicą w PHP. Ale co oznacza "coś []" w normalnym kontekście PHP? "[] "oznacza: utwórz nowy element wewnątrz "coś". Nowym elementem może być wszystko. Ale to, co chcesz wyrazić, to: tablica obiektów o tym samym typie i jego dokładnym typie. Jak widać, producent IDE wprowadza nowy kontekst. Nowy kontekst, którego musiałeś się nauczyć. Nowy kontekst inni programiści PHP musieli się nauczyć(aby zrozumieć Twoje dokumenty). Zły styl (!).

Ponieważ Twoja tablica ma jeden wymiar, może chcesz nazwać tę "tablicę obiektów" "listą". Należy pamiętać, że "lista" ma bardzo szczególne znaczenie w innych języki programowania. Lepiej byłoby nazwać to na przykład "kolekcją".

Pamiętaj: używasz języka programowania, który umożliwia Ci wszystkie opcje OOP. Użyj klasy zamiast tablicy i spraw, aby Twoja klasa była przemieszczana jak tablica. Np.:

class orderCollection implements ArrayIterator

Lub jeśli chcesz przechowywać wewnętrzne obiekty na różnych poziomach w wielowymiarowej tablicy / strukturze obiektu:

class orderCollection implements RecursiveArrayIterator

To rozwiązanie zastępuje tablicę obiektem typu "orderCollection", ale nie włącz do tej pory uzupełnianie kodu w swoim IDE. Ok. Następny krok:

Zaimplementuj metody, które są wprowadzane przez interfejs z docblocks-particular:

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

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

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

Nie zapomnij użyć podpowiedzi typu dla:

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

To rozwiązanie przestaje wprowadzać wiele:

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

Na wszystkich plikach kodu (np. w pętlach), co zahymaka potwierdził swoją odpowiedzią. Twój użytkownik API nie jest zmuszony do wprowadzenia tych blokad, aby mieć uzupełnianie kodu. Mieć @ return tylko na jednym miejsce zmniejsza redundancję (@var) tak mutch, jak to możliwe. Posypanie "docBlocks with @var" sprawi, że Twój kod będzie najbardziej czytelny.

W końcu jesteś skończony. Wygląda na trudną do osiągnięcia? Wygląda na to, że bierzesz młotek, żeby złamać orzech? Nie do końca, ponieważ jesteś zaznajomiony z tym interfejsem i czystym kodem. Pamiętaj: Twój kod źródłowy jest napisany raz / czytaj wiele.

Jeśli zakończenie kodu twojego IDE nie działa z tym podejściem, przełącz się na lepsze (np. IntelliJ IDEA, PhpStorm, Netbeans) lub złóż żądanie funkcji w monitorze problemów producenta IDE.

Podziękowania dla Christiana Weissa (z Niemiec) za bycie moim trenerem i za nauczenie mnie tak wspaniałych rzeczy. PS: Spotkajmy się z nim na XING.

 12
Author: DanielaWaranie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-01 20:27:26

Jak wspomniała DanielaWaranie w swojej odpowiedzi - istnieje sposób, aby określić typ $item, gdy iterujesz ponad $ items w $collectionObject: dodaj @return MyEntitiesClassName do current() i resztę Iterator i ArrayAccess-metod, które zwracają wartości.

Bum! nie ma potrzeby w /** @var SomeObj[] $collectionObj */ nad foreach i działa poprawnie z obiektem collection, nie ma potrzeby zwracania kolekcji określoną metodą opisaną jako @return SomeObj[].

Podejrzewam, że nie wszystkie IDE go obsługują, ale działa doskonale w PhpStorm, co sprawia, że ja jestem szczęśliwsza.

Przykład:

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
}

Co mi sie przydalo dodac ta odpowiedz

W moim przypadku current() i reszta interface-metody są zaimplementowane w klasie Abstract-collection i nie wiem, jakie encje zostaną ostatecznie zapisane w kolekcji.

Oto sztuczka: nie określaj typu return w klasie abstrakcyjnej, zamiast tego użyj instuction PhpDoc @method w opisie określonego zbioru klasy.

Przykład:

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

}

Użycie klas:

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

Jeszcze raz: podejrzewam, że nie wszystkie IDE go obsługują, ale PhpStorm tak. Wypróbuj swoje, napisz w komentarzu wyniki!

 5
Author: Pavel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-30 04:28:22

W NetBeans 7.0 (może być też niższy) Można zadeklarować typ zwracany "tablica z obiektami tekstowymi" tak jak @return Text i będzie działać hinting kodu:

Edit: zaktualizowano przykład z sugestią @ Bob Fanger

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

I po prostu użyj:

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

foreach($tests as $text){
    //$test->      //codehinting works!
}
To nie jest idealne, ale lepiej zostawić to po prostu "zmieszane", czarownica nie przynosi żadnej wartości.

Minusem jest to, że możesz stąpać po tablicy, ponieważ obiekt tekstowy rzuci błędy.

 4
Author: d.raev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-20 07:12:01

Użyj array[type] w Zend Studio.

W Zend Studio, array[MyClass] lub array[int] lub nawet array[array[MyClass]] działają świetnie.

 4
Author: Erick Robertson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-14 23:18:31

Problem polega na tym, że @var może oznaczać tylko jeden typ-nie zawiera złożonej formuły. Jeśli posiadasz składnię dla "array of Foo", to po co się zatrzymywać i nie dodawać składni dla "array of array, która zawiera 2 Foo' S I 3 Bar 's"? Rozumiem, że lista elementów jest być może bardziej ogólna, ale to śliska droga.

Osobiście kilka razy używałem @var Foo[] do oznaczenia "tablicy Foo 's", ale nie jest obsługiwana przez IDE ' s.

 2
Author: troelskn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-22 21:04:10
<?php foreach($this->models as /** @var Model_Object_WheelModel */ $model): ?>
    <?php
    // Type hinting now works:
    $model->getImage();
    ?>
<?php endforeach; ?>
 1
Author: Scott Hovestadt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-27 21:29:11

Wiem, że jestem spóźniony na imprezę, ale ostatnio pracowałem nad tym problemem. Mam nadzieję, że ktoś to widzi, ponieważ przyjęta odpowiedź, choć poprawna, jest , a nie najlepszym sposobem, aby to zrobić. Przynajmniej Nie w PHPStorm, nie testowałem jednak NetBeans.

Najlepszy sposób polega na rozszerzeniu klasy ArrayIterator zamiast używania natywnych typów tablic. Pozwala to na wpisanie podpowiedzi na poziomie klasy, a nie na poziomie instancji, co oznacza, że PHPDoc trzeba tylko raz, a nie w całym kodzie (który jest nie tylko niechlujny i narusza suchy, ale może być również problematyczny, jeśli chodzi o refaktoryzację-PHPStorm ma zwyczaj brakować PHPDoc podczas refaktoryzacji) {]}

Patrz kod poniżej:

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

Kluczem jest PHPDoc @method MyObj current() nadpisujący Typ powrotu odziedziczony z ArrayIterator (którym jest mixed). Włączenie tego PHPDoc oznacza, że gdy iterujemy nad właściwościami klasy używając foreach($this as $myObj), otrzymujemy dopełnienie kodu odwołując się do zmiennej $myObj->...

Dla mnie jest to najlepszy sposób, aby to osiągnąć (przynajmniej dopóki PHP nie wprowadzi wpisywanych tablic, jeśli kiedykolwiek to zrobią), ponieważ deklarujemy Typ iteratora w klasie iterable, a nie na instancjach klasy rozrzuconych po całym kodzie.

Nie pokazałem tutaj kompletnego rozwiązania dla rozszerzenia ArrayIterator, więc jeśli używasz tej techniki, możesz również chcieć:

  • zawierać inne PHPDoc na poziomie klasy, zgodnie z wymaganiami, dla metod takich jak offsetGet($index) i next()
  • Przenieś test sanity is_a($object, MyObj::class) z konstruktora do prywatnej metody
  • wywołaj ten (teraz prywatny) test sanity z nadpisań metod, takich jak offsetSet($index, $newval) i append($value)
 1
Author: e_i_pi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-23 00:21:18

Znalazłem coś, co działa, może uratować życie !

private $userList = array();
$userList = User::fetchAll(); // now $userList is an array of User objects
foreach ($userList as $user) {
   $user instanceof User;
   echo $user->getName();
}
 -5
Author: eupho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-13 10:43:15