In Larry's example, I could envision the usage of the same @param with the
code signatures of (array $things) as well as (iterable $things), and both
be acceptable.  Both seem to say "a collection Things", with the difference
being the expected retrieval mechanism in the code signature typehint
(array vs interable).

Granted, this doesn't help us much with the OP's use case, which centers
on @returns rather than @params.
CRB
*about.me/ashnazg <http://about.me/ashnazg>*


On Sat, Nov 10, 2018 at 11:02 AM Larry Garfield <la...@garfieldtech.com>
wrote:

> Hm, that's not quite what I mean.  IDEs would only need to do that level
> of
> deep inspection to generate a doc; I don't need them to generate it in
> this
> case if it's hard.
>
> I'm thinking more like:
>
> /**
>  * @param Things[] $things
>  */
> function do_stuff(iterable $things) {
>   // ...
> }
>
> The docblock here technically says "$things is an array of Thing objects",
> whereas the type declaration says "$things is an iterable that produces
> Thing
> objects".
>
> What should the @param statement be so that it matches the actual code?
>
> --Larry Garfield
>
> On Friday, November 9, 2018 12:33:00 PM CST Chuck Burgess wrote:
> > I don't immediately see a way to accomplish this with tags.
> >
> > The closest thing to an idea I can come up with here will be dictating a
> > rule to IDEs:  for any variable representing a collection used by a
> > foreach, the IDE must do deep class hierarchy mining to find *any and all
> > potential return mechanisms* in order to enumerate all possible return
> > types based on what's found.  In the OP's case,
> >
> > /* @var Stream $stream */
> > foreach ($stream as $item)
> >
> > that means the IDE must take the Stream interface, find all
> implementations
> > of it, find all known array/interable return methods, compile a list of
> > defined return types, and treat that list as what potential types that
> > $item might be.
> >
> > Is there any similar IDE behavior as a precedent for such a rule /
> > expectation?
> >
> >
> > Stepping back a moment... that /* @var */ usage... seems like I've only
> > ever seen that used to typehint the $item portion of the example, not the
> > $stream portion... $stream should have been figured out earlier when it
> was
> > first populated, either by its own /* @var */ doc or by the return type
> of
> > whatever function/method actually populated it.
> >
> > CRB
> > *about.me/ashnazg <http://about.me/ashnazg>*
> >
> >
> > On Fri, Nov 9, 2018 at 12:10 PM Larry Garfield <la...@garfieldtech.com>
> >
> > wrote:
> > > "This variable/return is an iterable of Foo objects" seems like an
> > > entirely
> > > reasonable thing to do.  We already have the de facto standard of
> Foo[] to
> > > mean "an array of Foo objects", but that doesn't technically cover any
> > > iterable.  (I'm really big on iterables these days, as anyone who
> follows
> > > my
> > > blog has noticed.)
> > >
> > > --Larry Garfield
> > >
> > > On Thursday, November 8, 2018 1:18:49 PM CST Chuck Burgess wrote:
> > > > Revisiting this, I'm leaning towards there *not* being a way to
> > >
> > > accomplish
> > >
> > > > this in the "one place" manner that you are after.
> > > > CRB
> > > >
> > > > On Wednesday, October 17, 2018 at 1:26:32 PM UTC-5, Woody Gilk wrote:
> > > > > Wouldn't the simple solution be:
> > > > >
> > > > > /** @var $stream Item[] */
> > > > > foreach ($stream as $item) {
> > > > >
> > > > >     /* ... */
> > > > >
> > > > > }
> > > > >
> > > > > On Tuesday, October 16, 2018 at 2:02:21 PM UTC-5, Alan Gabriel Bem
> > >
> > > wrote:
> > > > >> I think you missed my point - What I want to achieve is to
> *annotate*
> > > > >> somehow that *Stream* is *iterable* over *Item* object and do it
> in
> > >
> > > *one
> > >
> > > > >> place* instead of every place I'm using `Stream` implementation.
> > > > >>
> > > > >> As I mentioned I could enforce using *Iterator* or
> > > > >> *IteratorAggregate*
> > > > >> (as
> > > > >> it opens the way to specify the *Item* as an iterated type...
> which
> > >
> > > IDEs
> > >
> > > > >> understand), but I don't want to do that because actual iteration
> > >
> > > method
> > >
> > > > >> should depend on how it fits actual implementation. *Traversable*
> is
> > > > >> enough in this case because, simply speaking, it is marking
> *Stream*
> > >
> > > as
> > >
> > > > >> an object you can *foreach* on, but not telling how.
> > > > >>
> > > > >> wt., 16 paź 2018 o 19:30 Chuck Burgess <demon...@gmail.com>
> > >
> > > napisał(a):
> > > > >>> I'm tempted to argue that you're *not* sticking to Design By
> > > > >>> Contract
> > > > >>> here, because your two `Stream` implementations do not themselves
> > >
> > > give
> > >
> > > > >>> the
> > > > >>> same contract... at least, the parts of the contract that you're
> > >
> > > wanting
> > >
> > > > >>> to
> > > > >>> be derived by the IDE.
> > > > >>>
> > > > >>> Since it's already necessary to use a `/* @var */` comment block
> to
> > > > >>> typehint your local variable, and you don't want to hint
> > >
> > > specifically on
> > >
> > > > >>> your two classes, then perhaps you can do this instead:
> > > > >>>
> > > > >>> /* @var $stream Stream|Iterator|IteratorAggregate */
> > > > >>> foreach ($stream as $item) {
> > > > >>>
> > > > >>>     $item->...
> > > > >>>
> > > > >>> }
> > > > >>>
> > > > >>> That leaves you only hinting on interfaces...
> > > > >>> CRB
> > > > >>>
> > > > >>>
> > > > >>> On Saturday, October 13, 2018 at 5:06:26 PM UTC-5, Alan Gabriel
> Bem
> > > > >>>
> > > > >>> wrote:
> > > > >>>> It is easy if such interface already extends some kind of
> > >
> > > iterator...
> > >
> > > > >>>> interface Stream extends IteratorAggregate
> > > > >>>> {
> > > > >>>>
> > > > >>>>     /**
> > > > >>>>
> > > > >>>>      * @return Item[]
> > > > >>>>      */
> > > > >>>>
> > > > >>>>     public function getIterator();
> > > > >>>>
> > > > >>>> }
> > > > >>>>
> > > > >>>> ...or...
> > > > >>>>
> > > > >>>> interface Stream extends Iterator
> > > > >>>> {
> > > > >>>>
> > > > >>>>     /**
> > > > >>>>
> > > > >>>>      * @return Item
> > > > >>>>      */
> > > > >>>>
> > > > >>>>     public function current();
> > > > >>>>
> > > > >>>> }
> > > > >>>>
> > > > >>>> ...so IDEs have no problems with inferring actual type that
> > >
> > > variable of
> > >
> > > > >>>> type `Stream` iterates over...
> > > > >>>>
> > > > >>>> /* @var $stream Stream */
> > > > >>>> foreach ($stream as $item) {
> > > > >>>>
> > > > >>>>     $item->... // works, *Item* class methods are suggested
> > > > >>>>
> > > > >>>> }
> > > > >>>>
> > > > >>>> ...but what if we want to delay the decision of iteration
> > > > >>>> mechanism?
> > > > >>>> Like...
> > > > >>>>
> > > > >>>> interface Stream extends Traversable
> > > > >>>> {}
> > > > >>>>
> > > > >>>> ...so later on we can do this:
> > > > >>>>
> > > > >>>> class InMemoryStream implements Stream, IteratorAggregate
> > > > >>>> {
> > > > >>>>
> > > > >>>>     public function __construct(Item ...$items)
> > > > >>>>     {
> > > > >>>>
> > > > >>>>         $this->items = $items;
> > > > >>>>
> > > > >>>>     }
> > > > >>>>
> > > > >>>>     // rest of the code goes here
> > > > >>>>
> > > > >>>>     /**
> > > > >>>>
> > > > >>>>      * @return Item[]
> > > > >>>>      */
> > > > >>>>
> > > > >>>>     public function getIterator()
> > > > >>>>     {
> > > > >>>>
> > > > >>>>         return new ArrayIterator($this->items);
> > > > >>>>
> > > > >>>>     }
> > > > >>>>
> > > > >>>> }
> > > > >>>>
> > > > >>>> class DatabaseStream implements Stream, Iterator
> > > > >>>> {
> > > > >>>>
> > > > >>>>     // rest of the code goes here
> > > > >>>>
> > > > >>>>     public function rewind()
> > > > >>>>     {
> > > > >>>>
> > > > >>>>         $this->statement = $this->connection->prepare('SELECT *
> > > > >>>>         FROM
> > > > >>>>
> > > > >>>> items');
> > > > >>>>
> > > > >>>>         $this->statement->execute();
> > > > >>>>         $this->current =
> > > > >>>>         $this->statement->fetch(\PDO::FETCH_ASSOC);
> > > > >>>>         $this->key = 0;
> > > > >>>>
> > > > >>>>     }
> > > > >>>>
> > > > >>>>     public function next()
> > > > >>>>     {
> > > > >>>>
> > > > >>>>         $this->current =
> > > > >>>>         $this->statement->fetch(\PDO::FETCH_ASSOC);
> > > > >>>>         $this->key++;
> > > > >>>>
> > > > >>>>     }
> > > > >>>>
> > > > >>>>     public function key()
> > > > >>>>     {
> > > > >>>>
> > > > >>>>         return $this->key;
> > > > >>>>
> > > > >>>>     }
> > > > >>>>
> > > > >>>>     public function valid()
> > > > >>>>     {
> > > > >>>>
> > > > >>>>         return false !== $this->current;
> > > > >>>>
> > > > >>>>     }
> > > > >>>>
> > > > >>>>     /**
> > > > >>>>
> > > > >>>>      * @return Item
> > > > >>>>      */
> > > > >>>>
> > > > >>>>     public function current()
> > > > >>>>     {
> > > > >>>>
> > > > >>>>         return new Item($this->current);
> > > > >>>>
> > > > >>>>     }
> > > > >>>>
> > > > >>>> }
> > > > >>>>
> > > > >>>> Unfortunately IDEs, as can be expected, can't handle this.
> > > > >>>>
> > > > >>>> /* @var $stream Stream */
> > > > >>>> foreach ($stream as $item) {
> > > > >>>>
> > > > >>>>     $item->... // not enough information for IDEs to suggest
> type
> > >
> > > that
> > >
> > > > >>>> $stream iterates over.
> > > > >>>> }
> > > > >>>>
> > > > >>>> AFAIK at this moment the only solution for such case is to
> annotate
> > > > >>>> variables in user-land... every time.
> > > > >>>>
> > > > >>>> /* @var $stream Stream|A[] */
> > > > >>>> foreach ($stream as $item) {
> > > > >>>>
> > > > >>>>     $item->... // works
> > > > >>>>
> > > > >>>> }
> > > > >>>>
> > > > >>>> // or worse
> > > > >>>>
> > > > >>>> /* @var $stream DatabaseStream */
> > > > >>>> foreach ($stream as $item) {
> > > > >>>>
> > > > >>>>     $item->... // works but annotation specifies actual
> > >
> > > implementation
> > >
> > > > >>>> which violates Design by Contract principle
> > > > >>>> }
> > > > >>>>
> > > > >>>>
> > > > >>>>
> > > > >>>> It bugs me personally, but I would like to hear your opinion on
> > > > >>>> this
> > > > >>>> and possible solution.
> > >
> > > --
> > > You received this message because you are subscribed to the Google
> Groups
> > > "PHP Framework Interoperability Group" group.
> > > To unsubscribe from this group and stop receiving emails from it, send
> an
> > > email to php-fig+unsubscr...@googlegroups.com.
> > > To post to this group, send email to php-fig@googlegroups.com.
> > > To view this discussion on the web visit
> > > https://groups.google.com/d/msgid/php-fig/32811690.k7hq4Amyri%40vulcan
> .
> > > For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups
> "PHP Framework Interoperability Group" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to php-fig+unsubscr...@googlegroups.com.
> To post to this group, send email to php-fig@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/php-fig/1574651.KF4Rh9aDTK%40vulcan.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "PHP 
Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to php-fig+unsubscr...@googlegroups.com.
To post to this group, send email to php-fig@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/CANsgjnteWDDj4GvFLHE%3DvBGVQ5k9hprsF6OpQUCj8pbdyaBfrA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to