Re: Alias stdClass to DynamicObject?

From: 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.

« previous php.internals (#116012) next »