> On Sep 8, 2021, at 5:44 AM, Rowan Tommins <rowan.coll...@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.

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to