# Alias stdClass to DynamicObject?

- Thread: https://externals.io/message/115965
- Original archive: https://news-web.php.net/php.internals/115965
- Started by Nikita Popov on 2021-09-06T15:28:34+00:00
- Messages: 27
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/115965.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #115965 — Nikita Popov — 2021-09-06T15:28:34+00:00

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

Hi internals,

In the thread for deprecation of dynamic properties, Rowan suggested that
we alias "stdClass" to "DynamicObject" in
https://externals.io/message/115800#115802. I wanted to split this
discussion off into a separate thread, as this can be decided independently.

The rationale for this is that "stdClass" is something of a misnomer: The
name makes it sound like this is a common base class, as used in a number
of other languages. However, PHP does not have a common base class. The
only way in which "stdClass" is "standard" is that it is the return type of
casting an array to (object).

The actual role of stdClass is to serve as a container for dynamic
properties, thus the suggested DynamicObject name.

What do people think about adding such an alias? Is this worthwhile?

Regards,
Nikita

---

## #115967 — Benjamin Morel — 2021-09-06T16:08:59+00:00

URL: https://externals.io/message/115965#115967 · In reply to: #115965

Hi Nikita, Rowan,

In the thread for deprecation of dynamic properties, Rowan suggested that
> we alias "stdClass" to "DynamicObject" in
> https://externals.io/message/115800#115802. I wanted to split this
> discussion off into a separate thread, as this can be decided
> independently.
>
> The rationale for this is that "stdClass" is something of a misnomer: The
> name makes it sound like this is a common base class, as used in a number
> of other languages. However, PHP does not have a common base class. The
> only way in which "stdClass" is "standard" is that it is the return type of
> casting an array to (object).
>
> The actual role of stdClass is to serve as a container for dynamic
> properties, thus the suggested DynamicObject name.
>
> What do people think about adding such an alias? Is this worthwhile?


Yes, please! A future where dynamic properties are only allowed on
DynamicObject is bright.

I would even deprecate the stdClass alias straight away, so that the whole
thing can be gone in PHP 9.

Kind regards,
Benjamin

---

## #115968 — Christian Schneider — 2021-09-06T16:22:13+00:00

URL: https://externals.io/message/115965#115968 · In reply to: #115967

Am 06.09.2021 um 18:08 schrieb Benjamin Morel <benjamin.morel@gmail.com>:
> Yes, please! A future where dynamic properties are only allowed on
> DynamicObject is bright.

I have nothing against a DynamicObject alias for people who like to be more explicit in their code...

> I would even deprecate the stdClass alias straight away, so that the whole
> thing can be gone in PHP 9.

... but I'd prefer retaining a backward compatible version for library code, at least for a while and preferably without warnings :-)

- Chris

---

## #115970 — Kamil Tekiela — 2021-09-06T16:49:59+00:00

URL: https://externals.io/message/115965#115970 · In reply to: #115968

Hi Nikita,

I think this might be a good idea, but I would like to propose yet another
variant.
Replace stdClass with DynamicObject and keep stdClass as an alias. It can
be deprecated in 8.3.
If we only add an alias, I am afraid that it will not catch on quickly
enough. What I am proposing is that the cast to object will create
DynamicObject by default.

$arr = [1,2];
var_dump((object) $arr);
Output:
object(DynamicObject)#1 (2) {
  ["0"]=>
  int(1)
  ["1"]=>
  int(2)
}

It will break unit tests and it might break some code (e.g. `if ('stdClass'
=== $class)`), but it will help people understand what is the preferred
name going forward without deprecating it right now.

Regards,
Kamil

---

## #115972 — Matthew Brown — 2021-09-06T17:30:06+00:00

URL: https://externals.io/message/115965#115972 · In reply to: #115965

> 
> 

I think this would be a massive benefit to first-time PHP users one or two years from now.

I remember being confused by this terminology — I am sure bugs have been caused by people who assumed stdClass was a base class for all objects.

Best wishes,

Matt

---

## #115973 — Björn Larsson via internals — 2021-09-06T17:36:43+00:00

URL: https://externals.io/message/115965#115973 · In reply to: #115965

Den 2021-09-06 kl. 17:28, skrev Nikita Popov:
> Hi internals,
> 
> In the thread for deprecation of dynamic properties, Rowan suggested that
> we alias "stdClass" to "DynamicObject" in
> https://externals.io/message/115800#115802. I wanted to split this
> discussion off into a separate thread, as this can be decided independently.
> 
> The rationale for this is that "stdClass" is something of a misnomer: The
> name makes it sound like this is a common base class, as used in a number
> of other languages. However, PHP does not have a common base class. The
> only way in which "stdClass" is "standard" is that it is the return type of
> casting an array to (object).
> 
> The actual role of stdClass is to serve as a container for dynamic
> properties, thus the suggested DynamicObject name.
> 
> What do people think about adding such an alias? Is this worthwhile?
> 
> Regards,
> Nikita
> 

Well, we have legacy code where stdClass is quite prevalent and the code
works just fine!

In case of deprecation of stdClass I would like to point out that the
benefit of replacing "new stdClass" with "new DynamicObject" in our
existing code is absolutely zero. However, using DynamicObject in new
code has a benefit since the intent is clearer.

I think one also should take into account how much is stdClass described
in documentation and books. Reason is that deprecation is not just about
how it affects code. I'm a bit of a book worm so I'll check up on how
the usage of stdClass is described in some PHP books.

If deprecation of stdClass is on the table I think it should target the
last 8.x or 9.0 zero release.

r//Björn L

---

## #115977 — Aran Reeks — 2021-09-06T20:42:13+00:00

URL: https://externals.io/message/115965#115977

Creating a new DynamicObject class which is the preferred alias for
stdClass sounds logical but I too share the consern around making it the
default anytime soon. Too much code depends on an expected type of stdClass
presently which would likely make future upgrades more difficult for no
functional gain, beyond some added clarify.

With functions such as `json_decode()` still returning stdClass by default,
this is the main bug bare I can forsee where we commonly strict type
passing the decoded value throuh to another method or type. Would be nice
if in the future you could specify a class to populate instead of stdClass
- just a thought.

I too share the same view on deprecation notices being enfored and although
this would probably warrent its own thread, perhaps there benefit in
resolving this in itself under another RFC where a new php.ini directive,
or method call could be used to silence certain specified deprecation
warnings for those that are aware and understand the changes required in
the future so can knowingly make a decision to mute them.

On Mon, 6 Sep 2021, 18:50 Björn Larsson via internals, <
internals@lists.php.net> wrote:

> Den 2021-09-06 kl. 18:22, skrev Christian Schneider:
> > […]
> more explicit in their code...
> > […]
>
> Totally agree here!
>
> > […]
> whole
> > […]
> code, at least for a while and preferably without warnings :-)
> > […]
> Couldn't agree more on the statement "without warnings"!
>
> I mean if one have code that is in production, is running perfect and
> one wants to upgrade to the newest and fanciest PHP version and the
> logs are flooded with warnings for a deprecation with zero impact on
> functionality. What do one do? Maybe just turn of the warnings for
> that code section / library ;-)
>
> r//Björn L
>
> --
> 
> To unsubscribe, visit: https://www.php.net/unsub.php

---

## #115978 — Rowan Tommins — 2021-09-06T21:42:23+00:00

URL: https://externals.io/message/115965#115978 · In reply to: #115973

> In case of deprecation of stdClass I would like to point out that the
> benefit of replacing "new stdClass" with "new DynamicObject" in our
> existing code is absolutely zero. However, using DynamicObject in new
> code has a benefit since the intent is clearer. 


Just to mildly challenge this: Why is the intent of old code any less 
important? Do you never hire junior developers, or those cross-training 
from other languages, who have to maintain that code? Do you never have 
days where your brain is just a bit fuzzy, and every extra meaning you 
have to think about is one less line of code you'll get written?

But yes, for experienced PHP developers, the name is not that big a 
deal. Indeed, a lot of PHP developers probably never even see it. It's 
one of those little "paper cuts", where if we can make the fix not too 
painful (including deprecation messages not being too annoying), it will 
pay off in the long run.

Regards,

-- 
Rowan Tommins
[IMSoP]

---

## #115979 — Hossein Baghayi — 2021-09-07T01:05:23+00:00

URL: https://externals.io/message/115965#115979 · In reply to: #115977

> ... Too much code depends on an expected type of stdClass
> presently which would likely make future upgrades more difficult for no
> functional gain, beyond some added clarify.


What if we had the DynamicObject as a subclass of stdClass?
It would reduce the impact.

I don't know if aliasing works the same as with subclassing (regarding type
checking).

---

## #115984 — Nikita Popov — 2021-09-07T09:22:04+00:00

URL: https://externals.io/message/115965#115984 · In reply to: #115970

> Hi Nikita,
>
> I think this might be a good idea, but I would like to propose yet another
> variant.
> Replace stdClass with DynamicObject and keep stdClass as an alias. It can
> be deprecated in 8.3.
> If we only add an alias, I am afraid that it will not catch on quickly
> enough. What I am proposing is that the cast to object will create
> DynamicObject by default.
>
> $arr = [1,2];
> var_dump((object) $arr);
> Output:
> object(DynamicObject)#1 (2) {
>   ["0"]=>
>   int(1)
>   ["1"]=>
>   int(2)
> }
>
> It will break unit tests and it might break some code (e.g. `if ('stdClass'
> === $class)`), but it will help people understand what is the preferred
> name going forward without deprecating it right now.
>

My only apprehension with making stdClass rather than DynamicObject the
alias is the widespread impact this will have on extension testing code.
https://github.com/php/php-src/pull/7475 shows the approximate impact on
php-src. We need to update references to stdClass in `var_dump()` output in
more than 300 tests. We can do this easily, but it will be an inconvenience
for 3rd party extension tests that need to deal with more than one PHP
version.

Apart from that I agree that making DynamicObject the actual name and
stdClass the alias would be better.

Regards,
Nikita

---

## #115995 — Larry Garfield — 2021-09-07T14:18:27+00:00

URL: https://externals.io/message/115965#115995 · In reply to: #115984

> 
> 
> > […]
> 
> My only apprehension with making stdClass rather than DynamicObject the
> alias is the widespread impact this will have on extension testing code.
> https://github.com/php/php-src/pull/7475 shows the approximate impact on
> php-src. We need to update references to stdClass in `var_dump()` output in
> more than 300 tests. We can do this easily, but it will be an inconvenience
> for 3rd party extension tests that need to deal with more than one PHP
> version.
> 
> Apart from that I agree that making DynamicObject the actual name and
> stdClass the alias would be better.
> 
> Regards,
> Nikita

Adding the alias, I'm fully on board with.

Removing stdClass any time before PHP 10, I'm not on board with.  The user space breakage potential is too large to even be thinking about that at this point.

Flipping the alias around... again, I'm very concerned about the BC breakage.  Apparently `readonly` caused problems for Wordpress, which is doubleplusungood.  I would assume that we can't safely change which is the real name until proven otherwise, and based on Nikita's comments about PHP's own tests, I'd say it's definitely not proven otherwise.

--Larry Garfield

---

## #115996 — Marc Bennewitz — 2021-09-07T16:15:15+00:00

URL: https://externals.io/message/115965#115996 · In reply to: #115965

> Hi internals,
>
> In the thread for deprecation of dynamic properties, Rowan suggested that
> we alias "stdClass" to "DynamicObject" in
> https://externals.io/message/115800#115802. I wanted to split this
> discussion off into a separate thread, as this can be decided independently.
>
> The rationale for this is that "stdClass" is something of a misnomer: The
> name makes it sound like this is a common base class, as used in a number
> of other languages. However, PHP does not have a common base class. The
> only way in which "stdClass" is "standard" is that it is the return type of
> casting an array to (object).
>
> The actual role of stdClass is to serve as a container for dynamic
> properties, thus the suggested DynamicObject name.
>
> What do people think about adding such an alias? Is this worthwhile?

I do like the idea very much as "stdClass" is most confusion and also wrong.

The name "DynamicObject" is much better but I'm not sure if this is a 
good name either.

* It's a class -> Why do we suffix it with "Object"?

* Yes it's about dynamic properties - but is this the user goal to have 
dynamic properties or is it an implementation detail to get something 
else (map/dict)?

Wouldn't it be better to name it for what purpose it's being used 
(map/dict/ordered dict/...) instead of how this is done? And if we want 
to go that route we could also add common functionalities to it like 
getting list of keys/values converting to array iterating etc. it's 
already possible right know by casting to array but it would be more 
logically.

Yes we have assoc arrays in PHP to serve the purpose but this also has 
it's downsides as there is no type for it and the issue of converting an 
empty array from/to JSON (is it a list or a map?).

The big difference, of course, is the by-ref vs. by-value.


Hope that's not stupid questions?


Greetings,

Marc

---

## #115997 — Kamil Tekiela — 2021-09-07T17:28:34+00:00

URL: https://externals.io/message/115965#115997 · In reply to: #115996

Hi Marc,

The name seems to be ok IMHO. Even though it is a class, the main use case
is to denote an object that was created dynamically rather than through an
instantiation of a class. And I know that a lot of usage comes from people
directly creating new instances of stdClass but if you do that then you can
use proper classes also (with Nikita's proposal to deprecate dynamic
properties one would have to use a class with defined properties to do the
same).
It's not unheard that a class has "object" in the name. e.g.
https://docs.oracle.com/javaee/7/api/javax/json/JsonObject.html or
https://docs.microsoft.com/en-us/dotnet/api/system.json.jsonobject?view=dotnet-plat-ext-5.0
The name DynamicObject is also used in other languages.
https://docs.microsoft.com/en-us/dotnet/api/system.dynamic.dynamicobject?view=net-5.0
The word "Dynamic" semantically explains the purpose of the instance of
such class: it has no fixed structure.

We could call it Map or Dictionary, which would also be fitting, but in
doing so we are opening up the scope of this RFC. How much more
functionality does PHP need? What would be the goal of it? PHP has tons of
functions for working with arrays. If we introduce another type like Map
then it would be expected that a set of methods be added to it. This sounds
similar to scalar objects. And while it would be nice to have such kind of
functionality in PHP, it would also be a lot of work to implement it. If we
already have associative arrays, do we really need another structure to do
the same thing? I think it would be prudent to first understand why people
are using stdClass in the first place. From my experience, most of the time
people who work with stdClass don't expect it to have any methods. It's
just a container for data just like an array, but with a different syntax.
It's not much more different than an anonymous class.

The goal of Nikita's proposal is to retain the functionality of dynamically
assigning properties to an object after deprecating dynamic properties on
all other objects. The new class DynamicObject would be a special type of
class that would retain this functionality. Thus, the name fits perfectly.
A DynamicObject is a class whose properties can be created dynamically.

Regards,
Kamil

---

## #115999 — Levi Morrison via internals — 2021-09-08T03:02:32+00:00

URL: https://externals.io/message/115965#115999 · In reply to: #115965

>
> Hi internals,
>
> In the thread for deprecation of dynamic properties, Rowan suggested that
> we alias "stdClass" to "DynamicObject" in
> https://externals.io/message/115800#115802. I wanted to split this
> discussion off into a separate thread, as this can be decided independently.
>
> The rationale for this is that "stdClass" is something of a misnomer: The
> name makes it sound like this is a common base class, as used in a number
> of other languages. However, PHP does not have a common base class. The
> only way in which "stdClass" is "standard" is that it is the return type of
> casting an array to (object).
>
> The actual role of stdClass is to serve as a container for dynamic
> properties, thus the suggested DynamicObject name.
>
> What do people think about adding such an alias? Is this worthwhile?
>
> Regards,
> Nikita

If the alias goes to vote as the name DynamicObject, then I will
likely abstain. I don't care.

If it goes to vote under some other name, perhaps "map", or "dict",
then I would likely oppose it. I would like to keep those names
available for more useful features. There are multiple feature that
would like these names:
  1. Hacklang-style dict, which is a value-based dictionary type.
Importantly, this is copy-on-write like an array; it does not have
object semantics.
  2. In the event we ever add generics, it would be nice to have these
names available for interfaces.

I don't think an alias and replacement name for stdClass is important
enough to use these names.

---

## #116004 — Rowan Tommins — 2021-09-08T08:33:47+00:00

URL: https://externals.io/message/115965#116004 · In reply to: #115996

>
> * It's a class -> Why do we suffix it with "Object"?


Classes are generally named to make sense when you have an instance: a 
class called "HttpRequest" is not saying that the *class* is a request, 
but that every *instance* is one, as in "$myRequest = new HttpRequest;" 
Similarly, "DynamicObject" is not saying that the *class* is an object 
(or dynamic, for that matter), but that every instance is: "$myObject = 
new DynamicObject;"


> * Yes it's about dynamic properties - but is this the user goal to 
> have dynamic properties or is it an implementation detail to get 
> something else (map/dict)? 


I think a lot of uses of stdClass are precisely where people feel a map 
or dictionary *isn't* appropriate, and that's why they don't want to use 
an array: for instance, decoding a JSON string, or a database result 
row. The values aren't all of the same type, and you would never want to 
apply the same operation to all of them; you will probably initialise 
them once, and then access them by name, but don't have the facility to 
declare them up front.


Regards,

-- 
Rowan Tommins
[IMSoP]

---

## #116005 — Mike Schinkel — 2021-09-08T08:45:21+00:00

URL: https://externals.io/message/115965#116005 · In reply to: #115965

> 
> 
> Hi internals,
> 
> In the thread for deprecation of dynamic properties, Rowan suggested that
> we alias "stdClass" to "DynamicObject" in
> https://externals.io/message/115800#115802. I wanted to split this
> discussion off into a separate thread, as this can be decided independently.
> 
> The rationale for this is that "stdClass" is something of a misnomer: The
> name makes it sound like this is a common base class, as used in a number
> of other languages. However, PHP does not have a common base class. The
> only way in which "stdClass" is "standard" is that it is the return type of
> casting an array to (object).
> 
> The actual role of stdClass is to serve as a container for dynamic
> properties, thus the suggested DynamicObject name.
> 
> What do people think about adding such an alias? Is this worthwhile?

So I am trying to get around what this would actually mean in practice, and what the ramifications would be.

Given this proposal would `(object)array()` return an object of class 'DynamicObject' instead of 'stdClass'?

Will I be able to do a `new DynamicObject` just like I can currently do `new stdClass`?  I assume that instance would have a class of 'DynamicObject'?

And what of `new stdClass`?  Would `get_class(new stdClass)==='DynamicObject'` or would it continue to be `get_class(new stdClass)==='stdClass'`

Or would this be just like any class we can define today but that would still support dynamic properties whereas all other classes would disallow dynamic properties per the other proposal?

What about standard library functions that return a `stdClass` object?  (I assume there has to be at least one but I am not certain there is.). Assuming there are standard functions that return objects, will they now return 'DynamicObject' or still 'stdClass'?

===========

So while trying to get my head around the ramifications I prepared this bit of introspection, which is still missing some applicable tests I am sure:

https://3v4l.org/MDlOn#v8.0.10 <https://3v4l.org/MDlOn#v8.0.10>

===========

What I am struggling with here is to understand the vision for this change. Not that I find the change a bad idea — I do think it intimates a good direction — but at least as presented if feels like the vision for this may not have been fleshed out, or at least not fully communicated.

Maybe what I am looking for is a vision for what this change would mean for future PHP.  Is it just a special-cases that will cause as much confusion for developers trying to understand why there are too names for the same thing as it will help those who will better understand the new name, or is it more fully addressing the use-case for why people use dynamic objects?  

Maybe that's where we should start. I know there are some people who (I think) strongly argue that we should never use non-typed objects ever again but why do people use dynamic objects, still? This is a legitimate question, not a rhetorical, snide or sarcastic one. 

===========

So what are the use-cases where dynamic objects still make sense, and just as importantly what about those use-cases is still suboptimal besides just the class name? (I can think of a few, but want to hear from others before I explain mine.)

-Mike

---

## #116006 — Rowan Tommins — 2021-09-08T09:44:08+00:00

URL: https://externals.io/message/115965#116006 · In reply to: #116005

> So I am trying to get around what this would actually mean in practice, and what the ramifications would be.


The proposal is that the new name is an "alias" - the same class, but 
with two names. So the following would all create exactly the same object:

$obj = new stdClass;
$obj = new DynamicObject;
$obj = (object)[];

The following would be true for all of them:

assert( $obj instanceOf stdClass );
assert( $obj instanceOf DynamicObject );

There are some places that have to return some "real" name for the 
class, like get_class($obj). The current proposal is that "stdClass" be 
kept as the real name, at least initially, so you would see this:

$obj = new DynamicObject;
echo get_class($obj); // stdClass


> So while trying to get my head around the ramifications I prepared 
> this bit of introspection, which is still missing some applicable 
> tests I am sure:
>
> https://3v4l.org/MDlOn#v8.0.10


You can get a better idea of what's being proposed using the 
 `class_alias()` function, which lets you create an alias for a 
user-defined class: https://3v4l.org/a4EI0#v8.0.10


> Is it just a special-cases that will cause as much confusion for developers trying to understand why there are too names for the same thing as it will help those who will better understand the new name


That is certainly a risk, and a factor in favour of having some plan to 
retire the old name, even if only after a long overlap.


>   or is it more fully addressing the use-case for why people use dynamic objects?

The thread comes from a comment I made in Nikita's discussion about 
deprecating dynamic properties on normal objects. There was no grand 
vision behind it, just a long-standing dislike of the name "stdClass", 
and a concern that documenting "extends stdClass" as a way to enable 
dynamic properties on a custom class would make the confusion worse.


> So what are the use-cases where dynamic objects still make sense, and just as importantly what about those use-cases is still suboptimal besides just the class name?


To be honest, I think most uses of stdClass would be better served by 
anonymous classes, and would have been written that way if the feature 
had existed for longer. The one thing missing from anonymous classes 
right now is an elegant way to capture data from outer scope when you 
create them.


Regards,

-- 
Rowan Tommins
[IMSoP]

---

## #116007 — Nicolas Grekas — 2021-09-08T10:08:06+00:00

URL: https://externals.io/message/115965#116007 · In reply to: #115965

> In the thread for deprecation of dynamic properties, Rowan suggested that
> we alias "stdClass" to "DynamicObject" in
> https://externals.io/message/115800#115802. I wanted to split this
> discussion off into a separate thread, as this can be decided
> independently.
>
> The rationale for this is that "stdClass" is something of a misnomer: The
> name makes it sound like this is a common base class, as used in a number
> of other languages. However, PHP does not have a common base class. The
> only way in which "stdClass" is "standard" is that it is the return type of
> casting an array to (object).
>
> The actual role of stdClass is to serve as a container for dynamic
> properties, thus the suggested DynamicObject name.
>
> What do people think about adding such an alias? Is this worthwhile?
>

Hi Nikita, Rowan,

I'm reading the discussion about the side of the alias. Can't we solve
these concerns by making DynamicObject extend stdClass instead of aliasing?
That wouldn't allow an stdClass object to get through the DynamicObject
typehint, but that shouldn't be an issue since no such code has yet been
written, isn't it?

Nicolas

---

## #116008 — Rowan Tommins — 2021-09-08T12:01:23+00:00

URL: https://externals.io/message/115965#116008 · In reply to: #116007

> I'm reading the discussion about the side of the alias. Can't we solve 
> these concerns by making DynamicObject extend stdClass instead of 
> aliasing? That wouldn't allow an stdClass object to get through the 
> DynamicObject typehint, but that shouldn't be an issue since no such 
> code has yet been written, isn't it?


I've been pondering inheritance options, but I don't think they really 
help - whichever approach we use, one of these assertions will be false:

assert( new DynamicObject instanceof stdClass ); // false if stdClass is 
a sub-class of DynamicObject
assert( new stdClass instanceof DynamicObject ); // false if 
DynamicObject is a sub-class of stdClass
assert( get_class(new stdClass) === 'stdClass' ); // false if stdClass 
is an alias of DynamicObject
assert( get_class(new DynamicObject) === 'DynamicObject' ); // false if 
DynamicObject is an alias of stdClass

My guess would be that the name reported by get_class etc would mainly 
be used in tests and debugging, whereas instanceOf checks (and type 
constraints) will be used in actual "business logic" code paths. 
Existing code will expect "instanceOf stdClass" to work, and new code 
will expect "instanceOf DynamicObject" to work, so an alias (in either 
direction) seems the better compromise.

Regards,

-- 
Rowan Tommins
[IMSoP]

---

## #116012 — Mike Schinkel — 2021-09-08T15:37:56+00:00

URL: https://externals.io/message/115965#116012 · In reply to: #116006

> 
> > […]
> 
> That is certainly a risk, and a factor in favour of having some plan to retire the old name, even if only after a long overlap.

Ironically I believe if we add `DynamicObject` as an alias of `stdClass` where `DynamicObject::class === 'stdClass'` that would not provide much ability to retire `stdClass` any sooner than if we just deprecated it today. All future code that needs to refer to the class name will still refer to `stdClass`, so we won't be gaining much by creating an alias.

OTOH if we introduce a **completely new class** named `DynamicObject` having exactly the same behavior as a `stdClass` object (at least initialize) then we could add any new behavior to `DynamicObject` and leave `stdClass` fully in-tact for as long as we need to, except for notes in the docs that say to move to `DynamicObject` and tools like PhpStorm, Psalm and Phan could start suggesting a move away from `stdClass` right away.

With a new independent class `'DynamicObject' === get_class( new DynamicObject )` would always be true, and people who want to future proof their code could start replacing `stdClass` with `DynamicObject. People that don't (want to) make the change could maybe get a warning in PHP 9 and then maybe we remove `stdClass` in PHP and they must evolve or stick with PHP 8.

#fwiw I think `DynamicObject` is the best semantic name floated thus far albeit sadly on the rather long side.  `DynamicClass`, also long, could work too...

========

Of course having a different class begs the question of what  `get_class((object)array())` should return? Clearly for BC it needs to be `stdClass`, but as long as it is `stdClass` then we get no real benefit from aliasing with DynamicObject. 

Further, although the expression style of `(object)['prop' => 'value']` is the simplest way to initialize a basic `object` with literals in a single expression it is still a bad workaround that is far from intuitive for new developers, and feels like we are just leveraging an accidental capability rather than a well-designed language feature.  

If we want `DynamicObject` to eventually replace `stdClass` why not ALSO provide new syntax to give people a reason to switch to it? Why not leverage the named constructor concept but as a special case for `DynamicObject`, and only for `DynamicObject` (not `stdClass`); allow any arbitrary names to be used in constructor promotion?  Instead of this:

$obj = (object)array(
   "foo" => 1,
   "bar" => "hello",
   "baz" => true,
);o

We could do this instead:

$obj = new DynamicObject(
    foo: 1,
    bar: "hello",
    baz: true,
);

AND since we are talking a singular special case, why not also add a `DynamicObject()` function to streamline it a bit:

$obj = DynamicObject(
    foo: 1,
    bar: "hello",
    baz: true,
);

OR we could get inspired by the shortening of `function()` to `fn()` and used obj() (since `do()` is probably unworkable):

$obj = obj(
    foo: 1,
    bar: "hello",
    baz: true,
);

OR my personal favorite (though I know that would be a bridge too far for many) why not just this, too?

$obj = {
    foo: 1,
    bar: "hello",
    baz: true,
};

While we are at it, DynamicObject could add a few really useful methods such as `fromArray()`, `toJSON()` and more?  (And if I really want to get crazy, `toSqlUpdate()`, `toSqlInsert()`, etc, but now I fear I am just scaring people off.)

If we gave a better developer experience with literal initializers and useful methods then we've give a lot of developers reason to update their code to use `DynamicObject` and thus we could deprecate `stdClass` sooner. 

A couple more things; add a `JSON_OUTPUT_DYNAMIC_OBJECT` flag to output to DynamicObject for `json_decode()`,  add a 3rd parameter for flags to `var_export()` for the same reason, a `'return_dynamic_object'` option for `unserialize()`, and so on.

(BTW, we don't have to do ALL these things in one RFC. But we could go ahead and discuss the potential of having future RFCs that would add these features.)

> > […]
> 
> The thread comes from a comment I made in Nikita's discussion about deprecating dynamic properties on normal objects. There was no grand vision behind it, just a long-standing dislike of the name "stdClass", and a concern that documenting "extends stdClass" as a way to enable dynamic properties on a custom class would make the confusion worse.

Yes, I followed that discussion. But the fact you had a discussion doesn't ensure that the proposed solution is the proper one. Hence why I was trying to illicit a discussion about what would be more proper.

> The one thing missing from anonymous classes right now is an elegant way to capture data from outer scope when you create them.

I'm not exactly sure what that means, but if I had to guess I think maybe you are talking about a literally initialization syntax which is something I covered above?


-Mike

P.S. 

> There are some places that have to return some "real" name for the class, like get_class($obj). The current proposal is that "stdClass" be kept as the real name, at least initially, so you would see this:
> 
> $obj = new DynamicObject;
> echo get_class($obj); // stdClass

Yes, and that is where I see it to be most problematic, although admittedly for a built-in class with no predefined methods or properties the places where it could break an application are certainly many fewer than aliases for userland classes.  But I digress on this latter point...

> You can get a better idea of what's being proposed using the `class_alias()` function, which lets you create an alias for a user-defined class: https://3v4l.org/a4EI0#v8.0.10

Thanks for educating me on the existence of `class_alias()`; 12+ years of professional PHP and I can't remember ever noticing that existed.

If it didn't exist I would challenge why we need it, especially because it breaks the boolean which I had thought was true, that $class_name === get_class( new $class_name() ). But since it does exist me arguing that would be moot.

> > […]
> 
> To be honest, I think most uses of stdClass would be better served by anonymous classes, and would have been written that way if the feature had existed for longer.

Hmm. That seems like replacing apples with oranges.  

I assume we would also disallow dynamic properties in anonymous classes too, right? After all, they are just statically declared classes that the developer do not assign a name.

Anonymous class objects have different strengths and weaknesses and thus are useful in different contexts than dynamic objects.

> My guess would be that the name reported by get_class etc would mainly be used in tests and debugging, whereas instanceOf checks (and type constraints) will be used in actual "business logic" code paths. Existing code will expect "instanceOf stdClass" to work, and new code will expect "instanceOf DynamicObject" to work, so an alias (in either direction) seems the better compromise.

Besides, don't forget `stdClass::class` in addition to `get_class()`.

Anyway, with respect, I'd like to hear use-cases from others who are the ones saying they are using a lot of stdClass objects in their existing code. They may have insight that neither you nor I have on the topic.

---

## #116013 — Lynn — 2021-09-08T16:32:43+00:00

URL: https://externals.io/message/115965#116013 · In reply to: #116012

> A couple more things; add a `JSON_OUTPUT_DYNAMIC_OBJECT` flag to output to
> DynamicObject for `json_decode()`,  add a 3rd parameter for flags to
> `var_export()` for the same reason, a `'return_dynamic_object'` option for
> `unserialize()`, and so on.
>

It would also be interesting to enter a user-defined class here to work as
a reversed JsonSerializable. Could be a static factory method for all I
care, and would omit the requirement of serialization libraries for
"simple" things where you still want decent object typing. Could also work
together with interfaces accepting properties, effectively making the
result of json_decode an anonymous class that still adheres to an
interface. In case of the custom 'deserialization' you can throw exceptions
if the format is not correct. In the case of an anonymous class with an
interface it could throw an exception if the structure doesn't match
(possibly controlled by flags?).

---

## #116014 — Lynn — 2021-09-08T17:01:43+00:00

URL: https://externals.io/message/115965#116014 · In reply to: #115965

> What do people think about adding such an alias? Is this worthwhile?
>

What if `DynamicObject` becomes an interface instead of an alias? In the
future `stdClass` could be deprecated and replaced by anonymous classes
using the `DynamicObject` interface to prevent manual initialization. I
feel like renaming (this seems to be the end-goal) will not solve some of
the problems that `stdClass` brings to php. Hamza Ahmad brought the
interface up in the other thread: https://externals.io/message/115800#115806
.

```php
// core php
interface DynamicObject { /* ... /*}

// in case of removal, legacy support could be kept as
class stdClass implements DynamicObject {
    use DynamicObjectTrait; // perhaps also core php?
}

// a library wants a DynamicObject for whatever reason?
final class MyCustomDataObject implements DynamicObject {
    public function __get(string $name) : mixed {
        // as a developer I now have full control over where
        // this data comes from and is stored internally
    }
    /* ... */
}
```

To me it feels like making this an interface gives PHP more flexibility in
dealing with this in the future. One intermediate step could be to turn
`stdClass` into an interface that extends `DynamicObject`. 8.2 could
deprecate manual instantiation of `stdClass`, meaning that in 9.0 it could
be removed as class and turned into an interface, reducing the need to
update code relying on the `stdClass` types. `get_class` would still return
`stdClass` in 8.x and thus not break when using a `DynamicObject`.

---

## #116015 — Andreas Hennings — 2021-09-08T19:58:44+00:00

URL: https://externals.io/message/115965#116015 · In reply to: #116013

>
> 
>
> > […]
>
> It would also be interesting to enter a user-defined class here to work as
> a reversed JsonSerializable. Could be a static factory method for all I
> care, and would omit the requirement of serialization libraries for
> "simple" things where you still want decent object typing. Could also work
> together with interfaces accepting properties, effectively making the
> result of json_decode an anonymous class that still adheres to an
> interface. In case of the custom 'deserialization' you can throw exceptions
> if the format is not correct. In the case of an anonymous class with an
> interface it could throw an exception if the structure doesn't match
> (possibly controlled by flags?).

I think we want round-trips of `json_decode()` + `json_encode()` to work
loss-free, without any custom classes or extra parameters.

Currently, '{}' and '[]' have different results with `json_decode()`.

assert(json_encode(json_decode('{}')) === '{}');  // Perfect round-trip.
assert(json_encode(json_decode('{}', JSON_OBJECT_AS_ARRAY)) === '[]');
 // Lossy round-trip.

This can only work if we have a built-in data transfer object,
distinct from arrays.
Currently this is \stdClass, using the dynamic property mechanism.

But one could easily imagine a different kind of data transfer object,
which would use a different mechanism instead of dynamic properties.

A native implementation of JsonSerializable does not really work here,
because ->jsonSerialize() would have to return \stdClass to result in
'{}'.
Instead, what about something with a "->getData(): array" method, but
then `json_decode()` would encode it as '{}'?

assert(json_decode('{}') instanceof DataTransferObject);
assert(json_decode('{}')->getData() === []);
assert(json_encode(json_decode('{}')->getData()) === '[]');
assert(json_encode(json_decode('{}')) === '{}');

For the proposed rename:
- If we can fully deprecate and replace dynamic properties long-term,
I would rather keep the name \stdClass until it dies.
- Instead of an alias or rename, I would rather have a new data
transfer object class which would not rely on dynamic properties, but
on a new mechanism.

Imo, creating an alias won't actually make life easier for anyone,
unless we can fully remove and replace \stdClass.
It would mean that developers need to learn both names, and understand
how aliases work - something you don't really need to learn otherwise.
Think of the silly wtfs that can occur if people don't fully
understand aliases, or are not aware that DynamicObject is just an
alias, while \ReflectionClass and `get_class()` still return 'stdClass'
as the class name.

-- Andreas

---

## #116016 — Andreas Hennings — 2021-09-08T20:48:22+00:00

URL: https://externals.io/message/115965#116016 · In reply to: #116015

Wow!
I notice that ArrayObject already does everything we would need for
 `json_encode()`.

assert(json_encode(new ArrayObject([5])) === '{"0":5}');

However, it does so in a very strange way, not using any of the public
methods, but also not using dynamic properties.
It seems there is a hard-coded internal implementation when calling
 `json_encode()` or converting to array.
https://3v4l.org/rAc4K

I think we would want something more clean and transparent.







>
> 
> > […]
>
> I think we want round-trips of `json_decode()` + `json_encode()` to work
> loss-free, without any custom classes or extra parameters.
>
> Currently, '{}' and '[]' have different results with `json_decode()`.
>
> assert(json_encode(json_decode('{}')) === '{}');  // Perfect round-trip.
> assert(json_encode(json_decode('{}', JSON_OBJECT_AS_ARRAY)) === '[]');
>  // Lossy round-trip.
>
> This can only work if we have a built-in data transfer object,
> distinct from arrays.
> Currently this is \stdClass, using the dynamic property mechanism.
>
> But one could easily imagine a different kind of data transfer object,
> which would use a different mechanism instead of dynamic properties.
>
> A native implementation of JsonSerializable does not really work here,
> because ->jsonSerialize() would have to return \stdClass to result in
> '{}'.
> Instead, what about something with a "->getData(): array" method, but
> then `json_decode()` would encode it as '{}'?
>
> assert(json_decode('{}') instanceof DataTransferObject);
> assert(json_decode('{}')->getData() === []);
> assert(json_encode(json_decode('{}')->getData()) === '[]');
> assert(json_encode(json_decode('{}')) === '{}');
>
> For the proposed rename:
> - If we can fully deprecate and replace dynamic properties long-term,
> I would rather keep the name \stdClass until it dies.
> - Instead of an alias or rename, I would rather have a new data
> transfer object class which would not rely on dynamic properties, but
> on a new mechanism.
>
> Imo, creating an alias won't actually make life easier for anyone,
> unless we can fully remove and replace \stdClass.
> It would mean that developers need to learn both names, and understand
> how aliases work - something you don't really need to learn otherwise.
> Think of the silly wtfs that can occur if people don't fully
> understand aliases, or are not aware that DynamicObject is just an
> alias, while \ReflectionClass and `get_class()` still return 'stdClass'
> as the class name.
>
> -- Andreas

---

## #116017 — Rowan Tommins — 2021-09-08T20:59:38+00:00

URL: https://externals.io/message/115965#116017 · In reply to: #116012

> All future code that needs to refer to the class name will still refer to `stdClass`, so we won't be gaining much by creating an alias.


Just to be clear, the only code that would need to change is code that 
dynamically gets *out* the class name, from `get_class()`, `var_export()`, 
reflection, and the like. Using the class name in code, like "$foo = new 
stdClass;" and "$foo instanceof stdClass", would carry on working just 
fine, whichever way we defined the alias.


> Besides, don't forget `stdClass::class` in addition to `get_class()`.


The ::class syntax is purely string replacement (apart from some rare 
edge cases), and works identically whether the class exists, is an 
alias, or doesn't exist at all.


> I assume we would also disallow dynamic properties in anonymous classes too, right? After all, they are just statically declared classes that the developer do not assign a name.


The difference I see is that stdClass/DynamicObject allows you to add or 
remove properties from an object *after it has been created*. I think a 
lot of use cases don't actually need that, and would benefit from error 
messages when doing so accidentally.

You mentioned short-hand syntaxes like this:

> $obj = {
>      foo: 1,
>      bar: "hello",
>      baz: true,
> };

I would love for that, or some other short-hand, to be equivalent to this:

$obj = new class(foo: 1, bar: "hello", baz: true) {
     public $foo;
     public $bar;
     public $baz;
     public function __construct($foo, $bar, $baz) {
        $this->foo  = $foo;
        $this->bar = $bar;
        $this->baz = $baz;
     }
}

That is, an anonymous class, with exactly those three properties. If you 
*also* want to be able to define extra properties after it's created, 
you could opt into that using whatever mechanism a named class would 
(parent class, trait, attribute, etc; see other thread).

Similarly, the objects created by json_decode or PDO_FETCH_OBJECT only 
need the *initial* properties to be dynamic, not to allow properties to 
be added later.


Regards,

-- 
Rowan Tommins
[IMSoP]

---

Next page: https://externals.io/message/115965.md?page=2
