Re: Alias stdClass to DynamicObject?
| From: | Mike Schinkel | Date: | Wed, 08 Sep 2021 15:37:56 +0000 |
| Subject: | Re: Alias stdClass to DynamicObject? | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-116012@lists.php.net to get a copy of this message | ||
> On Sep 8, 2021, at 5:44 AM, Rowan Tommins <rowan.collins@gmail.com> wrote:
>> 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.
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.)
>> 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.
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.
>> 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.
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.