# Making stdClass iterable

- Thread: https://externals.io/message/103718
- Original archive: https://news-web.php.net/php.internals/103718
- Started by Craig Duncan on 2019-01-12T19:39:18+00:00
- Messages: 14
- RFC: Making stdClass iterable (Declined) — https://externals.io/rfc/iterable-stdclass.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #103718 — Craig Duncan — 2019-01-12T19:39:18+00:00

URL: https://externals.io/message/103718#103718

Hi everybody

I'd like to propose a change to stdClass so that it can satisfy the
iterable parameter/return type.

Firstly I acknowledge that this isn't an ideal solution, but I think it
gets us to a better state than we're in today. It shouldn't be necessary,
but while we have such a common function (json_decode) returning stdClass
we should make it easy/unsurprising to work with.

https://wiki.php.net/rfc/iterable-stdclass

Thanks,
Craig

---

## #103719 — Dan Ackroyd — 2019-01-12T20:13:41+00:00

URL: https://externals.io/message/103718#103719 · In reply to: #103718

Hi Duncan,

I quite strongly dislike the idea, as it sounds like this solution is
a hack for a particular use case, and that use case doesn't seem to be
particularly important to me.

I say it's not particularly important to me, as you could solve it right now by:

i) asking json_decode to return an array rather than an object.
ii) converting the result from json_decode into an object that
implements traversable.
iii) By accepted that PHP's type system isn't powerful enough to make
all programs trivially type-safe, and so to not use the iterable
parameter type here. This won't make your program any more or less
correct, it will just be slightly more annoying to debug.

Those seem to be better than special casing StdClass.

I say it's a hack as you're forcing the language to fit a particular
need with the available tools now, rather than thinking through what
best end-goal would be.

I think the correct long-term solution for this would be for us to
revisit the union type RFC (https://wiki.php.net/rfc/union_types) and
so be able to define a type like:

type foreachable = object|iterable;

The union types RFC would support the problem you're trying to solve,
as well as other use cases without introducing special cases.

cheers
Dan
Ack


>
> Hi everybody
>
> I'd like to propose a change to stdClass so that it can satisfy the
> iterable parameter/return type.
>
> Firstly I acknowledge that this isn't an ideal solution, but I think it
> gets us to a better state than we're in today. It shouldn't be necessary,
> but while we have such a common function (json_decode) returning stdClass
> we should make it easy/unsurprising to work with.
>
> https://wiki.php.net/rfc/iterable-stdclass
>
> Thanks,
> Craig

---

## #103720 — Markus Fischer — 2019-01-12T20:21:08+00:00

URL: https://externals.io/message/103718#103720 · In reply to: #103719

> Hi Duncan,
[...] great points

I was about to reply to Craig when Dans' email hit the list.

I couldn't agree with Dan more.

The expanded use of stdClass feels wrong to me, as in: wrong solution to 
a problem best solved differently. Dan gave ample examples about that.

I think one more approach not mentioned is that you could also `(array) 
$yourStdClassVar`. Of course you didn't ask for it, but nevertheless: 
stdClass is already a weird thing on its own and I wouldn't want to see 
it getting more attention to increase the encourage to use it.

cheers,
- Markus

---

## #103727 — Nikita Popov — 2019-01-14T11:57:06+00:00

URL: https://externals.io/message/103718#103727 · In reply to: #103718

> Hi everybody
>
> I'd like to propose a change to stdClass so that it can satisfy the
> iterable parameter/return type.
>
> Firstly I acknowledge that this isn't an ideal solution, but I think it
> gets us to a better state than we're in today. It shouldn't be necessary,
> but while we have such a common function (json_decode) returning stdClass
> we should make it easy/unsurprising to work with.
>
> https://wiki.php.net/rfc/iterable-stdclass
>
> Thanks,

Craig
>

Rather than implementing Traversable, I think it would be much better to
implement IteratorAggregate and provide a proper getIterator()
implementation. Objects that only implement Traversable are a PITA to work
with and lots of code assumes that anything Traversable will either be
Iterator or IteratorAggregate. For userland code this is strictly enforced,
but internal code can avoid this. However, the current exceptions to this
are rather niche, while stdClass is somewhat commonly used.

I'm in favor of the general change here. What I mainly have in mind is that
we should stop allowing iteration over arbitrary objects in the future (we
did the first step by excluding them from "iterable") and instead require
the use of an explicit PropertyIterator, or similar. However, we'd probably
still want to allow direct iteration of stdClass and the cleanest way to do
that is to make it Traversable (via IteratorAggregate).

Nikita

---

## #103728 — Craig Duncan — 2019-01-14T13:18:49+00:00

URL: https://externals.io/message/103718#103728 · In reply to: #103727

> Rather than implementing Traversable, I think it would be much better to
> implement IteratorAggregate and provide a proper getIterator()
> implementation. Objects that only implement Traversable are a PITA to work
> with and lots of code assumes that anything Traversable will either be
> Iterator or IteratorAggregate. For userland code this is strictly enforced,
> but internal code can avoid this. However, the current exceptions to this
> are rather niche, while stdClass is somewhat commonly used.
>

That makes sense, if the RFC passes I'll pick up these implementation
points before proceeding, thanks

---

## #103729 — Craig Duncan — 2019-01-14T13:23:24+00:00

URL: https://externals.io/message/103718#103729 · In reply to: #103719

> I think the correct long-term solution for this would be for us to
> revisit the union type RFC (https://wiki.php.net/rfc/union_types) and
> so be able to define a type like:
>
> type foreachable = object|iterable;
>

This argument makes sense to me in a pre-iterable world, but as we already
have an iterable type I don't understand why it shouldn't accept stdClass
as well as array.
What about an array is more iterable than a stdClass object?

---

## #103730 — Rowan Collins — 2019-01-14T14:48:00+00:00

URL: https://externals.io/message/103718#103730 · In reply to: #103727

> Rather than implementing Traversable, I think it would be much better to
> implement IteratorAggregate and provide a proper getIterator()
> implementation.


I think adding behaviour to stdClass is a precedent we should approach with
extreme caution.

Currently, it has no methods, and matches no type checks other than itself
and "object"; in a sense, it doesn't even have any properties, just the
ability to add them dynamically. To me, that makes sense: it's the
"classless object", the absolute bare minimum any object could be.



> What I mainly have in mind is that
> we should stop allowing iteration over arbitrary objects in the future (we
> did the first step by excluding them from "iterable") and instead require
> the use of an explicit PropertyIterator, or similar.


I agree that this should be explicit, and it could probably be implemented
as a very light wrapper.



> However, we'd probably still want to allow direct iteration of stdClass
>

Why? What do you consider the role of stdClass to be, that means having it
opt in to this behaviour would always be appropriate?

If you want something iterable, you can convert your stdClass object to an
array, wrap it an iterator that accepts any object, or convert it however
you want into a "proper" object where you can define what behaviour you
want.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #103731 — Rowan Collins — 2019-01-14T14:52:30+00:00

URL: https://externals.io/message/103718#103731 · In reply to: #103729

> What about an array is more iterable than a stdClass object?
>


An array is the structure PHP provides to represent a list, or an ordered
collection of arbitrary key-value pairs; an object, whether stdClass or
otherwise, is neither of these things.

I would instead ask: what about a stdClass object is more iterable than an
object created from a user-defined class?

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #103732 — Rowan Collins — 2019-01-14T14:58:09+00:00

URL: https://externals.io/message/103718#103732 · In reply to: #103730

> Currently, it has no methods, and matches no type checks other than itself
> and "object"; in a sense, it doesn't even have any properties, just the
> ability to add them dynamically. To me, that makes sense: it's the
> "classless object", the absolute bare minimum any object could be.
>

Apologies for the multiple replies, but it just occurred to me that with
anonymous classes, we can define something even more minimal:

$foo = new class {};
$bar = new stdClass;

Given that stdClass is returned as a "default structureless object" by a
lot of internal functions, what is the justification for $foo and $bar here
behaving differently?

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #103733 — Nikita Popov — 2019-01-14T15:00:23+00:00

URL: https://externals.io/message/103718#103733 · In reply to: #103730

On Mon, Jan 14, 2019 at 3:48 PM Rowan Collins <rowan.collins@gmail.com>
wrote:

> 
>
> > […]
>
>
> I think adding behaviour to stdClass is a precedent we should approach
> with extreme caution.
>
> Currently, it has no methods, and matches no type checks other than itself
> and "object"; in a sense, it doesn't even have any properties, just the
> ability to add them dynamically. To me, that makes sense: it's the
> "classless object", the absolute bare minimum any object could be.
>
>
>
> > […]
>
>
> I agree that this should be explicit, and it could probably be implemented
> as a very light wrapper.
>
>
>
> > […]
>
> Why? What do you consider the role of stdClass to be, that means having it
> opt in to this behaviour would always be appropriate?
>

The way I see it, stdClass is basically an array in object notation (and
object passing semantics). It carries data in the form of key value pairs
and has no associated logic. The only things you can do with it are access
keys (properties) and ... iterate over them.

Mind you, stdClass is an anti-pattern. Instead of stdClass you *should*
just be using an array. We should never have added stdClass. But now that
we do have it, and with the way it is typically being used, I think it's
fully appropriate to iterate over it.

That is much unlike most other (non-Traversable) objects, where iterating
over them is only reasonable in a few rather specific scenarios (say, a
serializer, cloner, hydrator or whatever -- something that explicitly is
interested in inspecting properties of objects as a matter of
representation).

Nikita


> If you want something iterable, you can convert your stdClass object to an
> array, wrap it an iterator that accepts any object, or convert it however
> you want into a "proper" object where you can define what behaviour you
> want.
>
> Regards,
> --
> Rowan Collins
> [IMSoP]

---

## #103734 — Rowan Collins — 2019-01-14T15:08:49+00:00

URL: https://externals.io/message/103718#103734 · In reply to: #103733

> The way I see it, stdClass is basically an array in object notation (and
> object passing semantics). It carries data in the form of key value pairs
> and has no associated logic. The only things you can do with it are access
> keys (properties) and ... iterate over them.
>
> [...] But now that we do have it, and with the way it is typically being
> used, I think it's fully appropriate to iterate over it.
>


I think it's the assumption about "the way it is typically being used"
where I differ from you. I generally see stdClass being used where people
want to access specific keys using -> notation, and maybe to get the
pass-by-pointer semantics. I'm not convinced that iterating over it as an
ordered collection is a sufficiently universal use case that it should be
an exception to the proposed rule of "objects aren't iterable unless
iteration logic has been defined".

I can see it might be convenient occasionally, but it feels like an
unnecessary special case, on top of a feature which I agree should be
discouraged anyway.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #103735 — Benjamin Morel — 2019-01-14T15:09:18+00:00

URL: https://externals.io/message/103718#103735 · In reply to: #103733

>  We should never have added stdClass.

Why not deprecate it then, instead of extending it and giving it more
legitimacy?
This would remove some of the "2 ways of doing the same thing", such as
 `json_decode()`.

Ben



> On Mon, Jan 14, 2019 at 3:48 PM Rowan Collins <rowan.collins@gmail.com>
> wrote:
>
> > […]
> itself
> > […]
> (we
> > […]
> require
> > […]
> implemented
> > […]
> it
> > […]
>
> The way I see it, stdClass is basically an array in object notation (and
> object passing semantics). It carries data in the form of key value pairs
> and has no associated logic. The only things you can do with it are access
> keys (properties) and ... iterate over them.
>
> Mind you, stdClass is an anti-pattern. Instead of stdClass you *should*
> just be using an array. We should never have added stdClass. But now that
> we do have it, and with the way it is typically being used, I think it's
> fully appropriate to iterate over it.
>
> That is much unlike most other (non-Traversable) objects, where iterating
> over them is only reasonable in a few rather specific scenarios (say, a
> serializer, cloner, hydrator or whatever -- something that explicitly is
> interested in inspecting properties of objects as a matter of
> representation).
>
> Nikita
>
>
> > […]
> an
> > […]

---

## #103736 — Marco Pivetta — 2019-01-14T15:17:52+00:00

URL: https://externals.io/message/103718#103736 · In reply to: #103735

On Mon, Jan 14, 2019 at 4:09 PM Benjamin Morel <benjamin.morel@gmail.com>
wrote:

> > […]
>
> Why not deprecate it then, instead of extending it and giving it more
> legitimacy?
> This would remove some of the "2 ways of doing the same thing", such as
> `json_decode()`.
>
> Ben
>

This.

`stdClass` can't die due to a lot of backwards compatibility in existing
code (wordpress loves it), but in any code I've written over the past 5
years, the first thing I'd do with it is get rid of it as fast as possible.

Making it more powerful will just make the problem bigger.

Marco Pivetta

http://twitter.com/Ocramius

http://ocramius.github.com/

---

## #103737 — Benjamin Morel — 2019-01-14T15:28:40+00:00

URL: https://externals.io/message/103718#103737 · In reply to: #103736

> `stdClass` can't die due to a lot of backwards compatibility in existing
code (wordpress loves it)

I, personally, would LOVE to see PHP break things on each release of a
major version!
I fail to see how upgrading could be painful, with a good changelog and the
right `E_DEPRECATED` notices for a minor release or two, enough time to make
it run in dev and even production, and working on deprecation notices as
they appear in the log; this would make the language move much faster
towards a better language.

But I digress.



> On Mon, Jan 14, 2019 at 4:09 PM Benjamin Morel <benjamin.morel@gmail.com>
> wrote:
>
> > […]
>
> This.
>
> `stdClass` can't die due to a lot of backwards compatibility in existing
> code (wordpress loves it), but in any code I've written over the past 5
> years, the first thing I'd do with it is get rid of it as fast as possible.
>
> Making it more powerful will just make the problem bigger.
>
> Marco Pivetta
>
> http://twitter.com/Ocramius
>
> http://ocramius.github.com/
