Подсказка типа PHPDoc для массива объектов?

Итак, в PHPDoc можно указать @var над объявлением переменной-члена, чтобы намекнуть на ее тип. Затем IDE, например. PHPEd будет знать, с каким типом объекта он работает, и сможет предоставить понимание кода для этой переменной.

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

Это отлично работает до тех пор, пока мне не понадобится сделать то же самое с массивом объектов, чтобы иметь возможность получить правильную подсказку, когда я буду перебирать эти объекты позже.

Итак, есть ли способ объявить тег PHPDoc, чтобы указать, что переменная-член является массивом SomeObjs? @var массива недостаточно, а @var array(SomeObj), например, кажется недействительным.


person Artem Russakovskii    schedule 22.04.2009    source источник
comment
В этом блоге разработчиков Netbeans 6.8 есть ссылка на то, что среда IDE теперь достаточно умна, чтобы определять тип членов массива: blogs.sun.com/netbeansphp/entry/php_templates_improved   -  person John Carter    schedule 17.10.2009
comment
@therefromhere: ваша ссылка не работает. Я думаю, что новый URL-адрес: blogs.oracle.com/netbeansphp/entry/php_templates_improved   -  person DanielaWaranie    schedule 17.10.2012
comment
Для людей вроде меня, проходящих мимо и ищущих ответ: если вы используете PHPStorm, посмотрите на ответ, получивший наибольшее количество голосов: в нем есть конкретная подсказка! stackoverflow.com/a/1763425/1356098 (это не означает, что это должен быть ответ для OP, поскольку он запрашивая PHPEd, например)   -  person Erenor Paz    schedule 24.11.2016


Ответы (13)


Использование:

/* @var $objs Test[] */
foreach ($objs as $obj) {
    // Typehinting will occur after typing $obj->
}

при вводе встроенных переменных и

class A {
    /** @var Test[] */
    private $items;
}

для свойств класса.

Предыдущий ответ от '09, когда в PHPDoc (и в IDE, таких как Zend Studio и Netbeans) не было этой опции:

Лучшее, что ты можешь сделать, это сказать:

foreach ($Objs as $Obj)
{
    /* @var $Obj Test */
    // You should be able to get hinting after the preceding line if you type $Obj->
}

Я часто этим занимаюсь в Zend Studio. Не знаю, как насчет других редакторов, но должно работать.

person Zahymaka    schedule 22.04.2009
comment
В этом есть смысл, но для PHPEd 5.2 это не сработало. Единственное, что мне удалось придумать, это сработало - это foreach ($ Objs as / ** @var Test * / $ Obj), что ужасно некрасиво. :( - person Artem Russakovskii; 22.04.2009
comment
Это работает в NetBeans 6.7 (я думаю, что это ошибка, поскольку вы получаете? Для типа, когда нажимаете ctrl-space, но он может автоматически заполнять элементы / методы объекта). - person John Carter; 30.09.2009
comment
Отлично работает в NetBeans 6.8+. $ Obj- ›затем ctrl-space вызывает ожидаемый список свойств и методов. - person Jon Cram; 07.05.2010
comment
Обратите внимание, что в Netbeans 7 кажется важным, что у вас есть только одна звездочка - /** @var $Obj Test */ не работает. - person contrebis; 13.06.2011
comment
@contrebis: @var - допустимый тег docblock. Так что, даже если ваша IDE не поддерживает его в пределах docblock / ** ... / и поддерживает только @var в / ... * / - пожалуйста, не меняйте ваш правильный docblock. Отправьте сообщение об ошибке в средство отслеживания ошибок вашей IDE, чтобы ваша IDE соответствовала стандартам. Представьте, что ваша команда разработчиков / внешние разработчики / сообщество используют разные IDE. Оставьте все как есть и будьте готовы к будущему. - person DanielaWaranie; 17.10.2012
comment
@DanielaWaranie Я не говорю, что вы ошибаетесь, но вы можете найти ссылку на это? Я могу найти только документацию, которая описывает @var как действительный для описания переменных класса. Я предположил, что использование @var в другом месте было полезным, но нестандартным расширением, отсюда и единственное *. - person contrebis; 17.10.2012
comment
Это решает проблему, но не подходит для чистого кода. Я думаю, нам нужно удалить / * @var $ Obj Test * / после того, как мы закончим нашу работу. Ты согласен со мной? - person Farid Movsumov; 19.11.2012
comment
Отметим, что это явно не работает с абстрактными классами. Поэтому, хотя мой массив гарантированно будет заполнен ТОЛЬКО подклассами Foo, я должен использовать пример одного из дочерних элементов, чтобы заставить его работать. - person RonLugge; 14.01.2013
comment
У меня работает, но почему после имени переменной пишется тип? Обычно бывает наоборот ... - person andreas; 10.08.2013
comment
Убедитесь, что вы смотрите ниже! Я почти не прокрутил вниз - это была бы БОЛЬШАЯ ОШИБКА !!! Многие IDE БУДУТ поддерживать лучший синтаксис! (подсказка: @var Object[] $objects говорит, что $ objects - это массив экземпляров Object.) - person Thom Porter; 30.08.2013
comment
/** @var TYPE $variable_name */ - правильный синтаксис; не меняйте порядок типов и имен переменных (как предлагалось ранее в комментариях), так как это не будет работать во всех случаях. - person srcspider; 29.11.2013
comment
Я должен согласиться с Томом Портером. Действительно, этот синтаксис поддерживается phpDocumentor. См. phpdoc.org/docs/latest/guides/types.html#arrays и еще одна тема по той же теме stackoverflow.com/questions/9132062/! - person Jérôme; 22.08.2014
comment
Хотя этот ответ интересен, это не лучший ответ. Я бы хотел, чтобы Stack Overflow позволил сообществу изменить принятый ответ на основе голосов. Не забудьте найти лучший ответ ниже. - person Mr. Lance E Sloan; 21.05.2015
comment
@var User[] - это ответ - person Ejaz; 10.11.2015
comment
Ответ ниже верен для всех, кто ищет (это то, что я использую). В то время, когда задавался этот вопрос ('09), PHPStorm был очень новым, и синтаксис SomeObj [] не поддерживался во многих IDE. - person Zahymaka; 11.11.2015
comment
@zahymaka, я думаю, вам следует удалить свой ответ, так как он больше не правильный и теперь дает людям неверную информацию. Или, по крайней мере, отредактируйте его, чтобы отразить, что он больше не точен. - person Ian Dunn; 18.10.2018
comment
@Zahymaka - Как мы можем создавать исключения для несоответствия типов? - person kta; 08.06.2019

В IDE PhpStorm от JetBrains вы можете использовать /** @var SomeObj[] */, например:

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

В документации по phpdoc рекомендуется этот метод:

указано, что содержит единственный тип, определение типа информирует читателя о типе каждого элемента массива. Тогда ожидается, что в качестве элемента для данного массива будет только один тип.

Пример: @return int[]

person Nishi    schedule 19.11.2009
comment
Я только что скачал и использую phpstorm последнюю неделю. Лучше всего Aptana (что отлично для того, чтобы быть бесплатным). Это именно то, что я искал. На самом деле, это то же самое, что и для JavaScript, я должен был догадаться - person Juan Mendes; 07.10.2010
comment
Это не работает в Netbeans, я разочарован. Jetbrains создают очень хорошие инструменты. - person Keyo; 30.08.2011
comment
Спасибо! Я пытался найти правильный синтаксис в PhpStorm. Знал, что у них что-нибудь есть. Я нашел бы array<SomeObj> более интуитивным. Но я предполагаю, что это из моего фона C ++ / C # (шаблонные vars). - person mpen; 03.12.2011
comment
Можем ли мы сделать аннотацию совместимой с NetBeans, используя /** @var SomeObj[]|array */? - person fishbone; 13.01.2012
comment
@fishbone @Keyo это работает в Netbeans сейчас (по крайней мере, в ночной сборке 7.1, может быть, раньше), хотя кажется, что вам нужно использовать временную переменную (ошибка?). Намек на foreach(getSomeObjects() as $obj) не работает, но работает для $objs = getSomeObjects(); foreach($objs as $obj) - person John Carter; 21.01.2012
comment
Теперь это полностью работает в последних ночных сборках Netbeans и должно быть включено в выпуск 7.2. - person John Carter; 22.04.2012
comment
Работает в NuSphere PhpED. - person Dyin; 30.06.2013
comment
У меня есть программа, которая создает для меня базовые файлы MVC на основе структуры базы данных, и с самого начала у меня была она, включая комментарии блока документации к файлам представления для всех определенных переменных. Я только что обновил его, чтобы использовать этот УДИВИТЕЛЬНЫЙ формат _1 _... Мне это НРАВИТСЯ! Спасибо команде JetBrains, и я благодарю SO за правильные ответы! знак равно - person Thom Porter; 30.08.2013
comment
Было бы неплохо иметь @var Obj[string] для ассоциативных массивов. - person donquixote; 02.12.2013
comment
К сожалению, Komodo IDE (начиная с версии 8.5) поддерживает его лишь частично: [] в конце подсказки не имеет значения, komodo считает, что возвращает этот тип (отдельный объект). - person Attila Fulop; 26.02.2014
comment
Следует упомянуть также о работе в intellij Ultimate, а также в phpstorm - person aqm; 04.04.2014
comment
Обратите внимание, что вы должны поместить его здесь: / ** @var EditablePane [] $ Panes / public $ Panes; Не здесь: public / * var EditablePane [] $ Panes * / $ Panes; - person Jonathan; 15.05.2014
comment
Также работает в PHP Tools для Visual Studio. - person Joey Adams; 21.10.2014
comment
У меня не работает в PhpStorm 8.0.3. Если у меня есть @return \namespace\Class[] в моем док-блоке, он не отображается во всплывающем окне документации (ctrl + q). - person Nate; 20.05.2015
comment
Это определенно лучший ответ, чем принятый. Приветствую @Nishi;), который, наверное, помог тысячам людей справиться с их проблемами. - person Kalko; 04.08.2016
comment
Вы также можете комбинировать синтаксисы [] и |, чтобы указать массив смешанных типов: /** @var A[]|B[] $Obj */ будет указывать, что $Obj является смешанным массивом из экземпляров A и B, и когда вы выполняете итерацию массива (foreach), PhpStorm (возможно, другие к настоящему времени?) показать все, что доступно из A и B для текущего элемента. Это немного сбивает с толку, учитывая, что синтаксис подразумевает массив A ИЛИ массив B, но это работает. - person cautionbug; 09.08.2016
comment
Для массивов, которые могут содержать несколько типов, phpDocumentor указывает синтаксис как (A|B)[] и поддерживается PHPStorm. - person gapple; 17.01.2017
comment
Извините, я приверженец, люди говорят, что PHPStorm великолепен, но, конечно, для тех, кто работает сразу с несколькими полными стеками, такими как php / laravel, ruby ​​/ rails, Java и Angular JS, IntelliJ также so great с соответствующими плагинами установлен;) Нет необходимости связывать массу оперативной памяти с несколькими IDE, такими как phpstorm + rubymine + intelliJ и т. д. - person wired00; 23.01.2017

Подсказки Netbeans:

Вы получаете завершение кода для $users[0]-> и для $this-> для массива классов User.

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

Вы также можете увидеть тип массива в списке членов класса, когда завершите $this->...

person user1491819    schedule 02.05.2015
comment
также работает в PhpStorm 9 EAP: / ** * @var UserInterface [] * / var $ users = []; // Массив объектов, реализующих интерфейс - person Ronan; 27.05.2015
comment
Я пробовал это в IDE NetBeans 8.0.2, но получаю предложения от класса, в котором я сейчас участвую. - person Wojciech Jasiński; 24.07.2015
comment
также работает в Eclipse 4.6.3 (idk, какая версия поддержки была введена, но она работает, и это то, что я использую сейчас) - person hanshenrik; 18.06.2017
comment
К сожалению, это не работает после использования array_pop() или аналогичных функций по какой-то причине. Похоже, Netbeans не понимает, что эти функции возвращают единственный элемент входного массива. - person William W; 02.06.2019

Чтобы указать переменную, представляет собой массив объектов:

$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 не обязательно.

person Highmastdon    schedule 01.01.2013
comment
На мой взгляд, это решение чище, чем принятый ответ, потому что вы можете использовать foreach несколько раз, и подсказка типа будет продолжать работать без новой аннотации /* @var $Obj Test */ каждый раз. - person Henry; 05.11.2014
comment
Я вижу здесь две проблемы: 1. правильный phpdoc начинается с /** 2. Правильный формат - @var <data-type> <variable-name> - person Christian; 28.02.2016
comment
@Christian 1: главный вопрос не в phpdoc, а в типе 2: правильный формат не такой, как вы говорите, даже согласно другим ответам. На самом деле, я вижу 2 проблемы с вашим комментарием, и мне интересно, почему вы не даете свой собственный ответ в правильном формате - person Highmastdon; 28.02.2016
comment
1. Набор текста работает с phpdoc ... если вы не используете docblock, ваша IDE не будет пытаться угадать, что вы написали в каком-то случайном комментарии. 2. Правильный формат, как сказано в некоторых других ответах, - это то, что я указал выше; тип данных перед именем переменной. 3. Я не написал еще один ответ, потому что для этого вопроса не нужен еще один, и я бы предпочел не просто редактировать ваш код. - person Christian; 28.02.2016
comment
Хотя это работает, автозаполнение (введите /**<space>, и оно будет расширено, чтобы включить следующее имя переменной) ожидает тип перед именем переменной, поэтому /** @var Needle[] $needles */ (PHPStorm 2021.1) - person Dave Meehan; 11.05.2021

PSR-5: PHPDoc предлагает форма нотации в стиле Generics.

Синтаксис

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

Из моего ответа на этот вопрос.

person Gerard Roche    schedule 09.09.2016
comment
Общая нотация была удалена из PSR-5 - person zored; 27.11.2018

Я предпочитаю читать и писать чистый код - как описано в «Чистом коде» Роберта К. Мартина. Следуя его кредо, вы не должны требовать, чтобы разработчик (как пользователь вашего API) знал (внутреннюю) структуру вашего массива.

Пользователь API может спросить: это массив только с одним измерением? Распространены ли объекты по всем уровням многомерного массива? Сколько вложенных циклов (foreach и т. Д.) Мне нужно для доступа ко всем объектам? Какие типы объектов «хранятся» в этом массиве?

Как вы обрисовали в общих чертах, вы хотите использовать этот массив (содержащий объекты) как одномерный массив.

Как указано Ниши, вы можете использовать:

/**
 * @return SomeObj[]
 */

для этого.

Но опять же: имейте в виду - это не стандартная нотация докблока. Это обозначение было введено некоторыми производителями IDE.

Хорошо, хорошо, как разработчик вы знаете, что «[]» привязан к массиву в PHP. Но что означает «что-то []» в обычном контексте PHP? «[]» означает: создать новый элемент внутри «чего-то». Новый элемент может быть чем угодно. Но вы хотите выразить следующее: массив объектов одного и того же типа и его точного типа. Как видите, производитель IDE вводит новый контекст. Новый контекст, который вам нужно было изучить. Новый контекст, который пришлось изучить другим PHP-разработчикам (чтобы понять ваши док-блоки). Плохой стиль (!).

Поскольку ваш массив действительно имеет одно измерение, вы, возможно, захотите назвать этот «массив объектов» «списком». Имейте в виду, что «список» имеет особое значение в других языках программирования. Было бы лучше называть это, например, "сбором".

Помните: вы используете язык программирования, который позволяет вам использовать все возможности ООП. Используйте класс вместо массива и сделайте свой класс проходимым, как массив. Например.:

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

во всех ваших файлах кода (например, внутри циклов), как подтвердил Захимака своим ответом. Ваш пользователь API не обязан вводить эти докблоки для завершения кода. Наличие @return только в одном месте максимально снижает избыточность (@var). Если добавить в docBlocks @var, код будет хуже читаться.

Наконец-то все готово. Выглядит сложно? Похоже, чтобы сломать орех кувалдой? Не совсем так, поскольку вы знакомы с этими интерфейсами и с чистым кодом. Помните: ваш исходный код пишется один раз / читается много раз.

Если автозавершение кода вашей IDE не работает с этим подходом, переключитесь на более подходящий вариант (например, IntelliJ IDEA, PhpStorm, Netbeans) или отправьте запрос функции в средство отслеживания проблем вашего производителя IDE.

Спасибо Кристиану Вайсу (из Германии) за то, что он был моим тренером и научил меня такому замечательному материалу. PS: Встретимся с ним на XING.

person DanielaWaranie    schedule 16.10.2012
comment
это похоже на правильный путь, но я не могу заставить его работать с Netbeans. Сделал небольшой пример: imgur.com/fJ9Qsro - person fehrlich; 11.11.2013
comment
Возможно, в 2012 году это не было стандартом, но сейчас это описано как встроенная функциональность phpDoc. - person Wirone; 25.07.2014
comment
@Wirone похоже, что phpDocumentor добавляет это в свое руководство как реакция на производителей ide. Даже если у вас есть широкая поддержка инструментов, это не значит, что это лучшая практика. SomeObj [] начинает распространяться во все большем количестве проектов, как и require, require_once, include и include_once много лет назад. При автозагрузке видимость этих утверждений падает ниже 5%. Надеюсь, SomeObj [] упадет до той же скорости в течение следующих 2 лет в пользу подхода, описанного выше. - person DanielaWaranie; 28.07.2014
comment
Я не понимаю почему? Это очень простые и понятные обозначения. Когда вы видите SomeObj[], вы знаете, что это двумерный массив SomeObj экземпляров, и тогда вы знаете, что с ним делать. Я не думаю, что это не соответствует кредо чистого кода. - person Wirone; 29.07.2014
comment
Это должен быть ответ. Однако не все IDE поддерживают подход @return <className> для current() и всех ребят. PhpStorm поддерживает, поэтому мне это очень помогло. Спасибо друг! - person Pavel; 30.10.2014

Используйте array[type] в Zend Studio.

В Zend Studio отлично работают array[MyClass], array[int] или даже array[array[MyClass]].

person Erick Robertson    schedule 14.04.2014

В NetBeans 7.0 (может быть и ниже) вы можете объявить возвращаемый тип «массив с текстовыми объектами» так же, как @return Text, и подсказка кода будет работать:

Изменить: обновлен пример с предложением @Bob Fanger.

/**
 * 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!
}

Он не идеален, но лучше оставить его просто «смешанным», что не приносит никакой пользы.

МИНУСЫ - вам разрешено использовать массив как текстовый объект, который будет вызывать ошибки.

person d.raev    schedule 06.02.2013
comment
Я использую массив @return | Тест Некоторое описание. который вызывает такое же поведение, но требует более подробного объяснения. - person Bob Fanger; 26.03.2013
comment
Это обходной путь, а не решение. Здесь вы говорите, что эта функция может возвращать объект типа Test ИЛИ массив. Однако технически он ничего не говорит вам о том, что может быть в массиве. - person Byson; 21.09.2015

Как отметила Даниэла Варани в своем ответе, есть способ указать тип $ item при итерации по $ items в $ collectionObject: добавить @return MyEntitiesClassName в current() и остальные методы Iterator и ArrayAccess, которые возвращают значения.

Бум! Нет необходимости в /** @var SomeObj[] $collectionObj */ поверх 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-методы реализованы в классе Abstract-collection, и я не знаю, какие объекты в конечном итоге будут храниться в коллекции.

Итак, вот трюк: не указывайте тип возвращаемого значения в абстрактном классе, вместо этого используйте инструкцию PhpDoc @method в описании конкретного класса коллекции.

Пример:

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 поддерживает. Попробуйте свой, оставьте в комментариях результаты!

person Pavel    schedule 30.10.2014
comment
Купон на то, что зашел так далеко, но, к сожалению, я все еще могу решить специализировать коллекцию, чтобы заменить старые добрые общие типы java .... фу '' - person Sebas; 11.02.2016
comment
Спасибо. Как вы можете напечатать статический метод? - person Yevgeniy Afanasyev; 26.09.2018

Я знаю, что опаздываю на вечеринку, но недавно работал над этой проблемой. Я надеюсь, что кто-то это увидит, потому что принятый ответ, хотя и правильный, не является лучшим способом сделать это. По крайней мере, не в PHPStorm, но я не тестировал NetBeans.

Лучший способ - это расширение класса ArrayIterator, а не использование собственных типов массивов. Это позволяет вам вводить подсказку на уровне класса, а не на уровне экземпляра, что означает, что вам нужно использовать PHPDoc только один раз, а не во всем коде (что не только беспорядочно и нарушает 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();

Ключевым моментом здесь является PHPDoc @method MyObj current(), переопределяющий тип возвращаемого значения, унаследованный от ArrayIterator (это mixed). Включение этого PHPDoc означает, что когда мы перебираем свойства класса с помощью foreach($this as $myObj), мы получаем завершение кода при обращении к переменной $myObj->...

Для меня это лучший способ добиться этого (по крайней мере, до тех пор, пока PHP не представит типизированные массивы, если они когда-либо будут), поскольку мы объявляем тип итератора в повторяемом классе, а не в экземплярах класса, разбросанных по всему коду.

Я не показал здесь полное решение для расширения ArrayIterator, поэтому, если вы воспользуетесь этим методом, вы также можете:

  • При необходимости включите другой PHPDoc уровня класса для таких методов, как offsetGet($index) и next()
  • Переместите проверку работоспособности is_a($object, MyObj::class) из конструктора в частный метод
  • Вызовите эту (теперь частную) проверку работоспособности из переопределений методов, таких как offsetSet($index, $newval) и append($value)
person e_i_pi    schedule 23.12.2016
comment
Очень красивое и чистое решение! :) - person Marko Šutija; 07.01.2019

Проблема в том, что @var может обозначать только один тип - не содержать сложной формулы. Если у вас есть синтаксис для «array of Foo», зачем останавливаться на этом и не добавлять синтаксис для «массива массива, содержащего 2 Foo и три Bar»? Я понимаю, что список элементов, возможно, более общий, чем этот, но это скользкая дорожка.

Лично я несколько раз использовал @var Foo[] для обозначения «массива Foo», но это не поддерживается IDE.

person troelskn    schedule 22.04.2009
comment
Что мне нравится в C / C ++, так это то, что он отслеживает типы вплоть до этого уровня. Было бы очень приятно спуститься по склону. - person Brilliand; 03.05.2011
comment
Поддерживается Netbeans 7.2 (по крайней мере, это та версия, которую я использую), но с небольшой настройкой, а именно: /* @var $foo Foo[] */. Просто написал об этом ниже ответ. Это также можно использовать внутри foreach(){} циклов - person Highmastdon; 01.01.2013

Я нашел кое-что, что работает, это может спасти жизни!

private $userList = array();
$userList = User::fetchAll(); // now $userList is an array of User objects
foreach ($userList as $user) {
   $user instanceof User;
   echo $user->getName();
}
person eupho    schedule 13.01.2010
comment
Единственная проблема заключается в том, что вводится дополнительный код для выполнения, который используется только вашей IDE. Вместо этого гораздо лучше определить подсказку типа в комментариях. - person Ben Rowe; 28.01.2010
comment
Ух ты, это отлично работает. В итоге вы получите дополнительный код, но он кажется безвредным. Я собираюсь начать делать: $ x instanceof Y; // подсказка - person Igor Nadj; 06.09.2010
comment
Переключитесь на IDE, которая дает вам автозавершение кода на основе блоков документов или проверок. Если вы не хотите переключать свой файл IDE, запросите функцию в системе отслеживания проблем вашей IDE. - person DanielaWaranie; 17.10.2012
comment
Если это вызывает исключение, если тип неверен, это может быть полезно для проверки типа во время выполнения. Если... - person lilbyrdie; 05.09.2014

person    schedule
comment
Это очень некрасиво. Попрощайтесь с чистым кодом, когда начинаете программировать таким образом. - person halfpastfour.am; 04.09.2012
comment
Лучше посмотрите мой ответ с определением содержимого массива: stackoverflow.com/a/14110784/431967 - person Highmastdon; 14.05.2013