Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:116012 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 33200 invoked from network); 8 Sep 2021 15:00:18 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 8 Sep 2021 15:00:18 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 03EF0180510 for ; Wed, 8 Sep 2021 08:38:01 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-qv1-f46.google.com (mail-qv1-f46.google.com [209.85.219.46]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 8 Sep 2021 08:38:00 -0700 (PDT) Received: by mail-qv1-f46.google.com with SMTP id 93so1721092qva.7 for ; Wed, 08 Sep 2021 08:38:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=newclarity-net.20150623.gappssmtp.com; s=20150623; h=mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=mgD3Cyxxudgq1gSLJurDa9ndROZwZFFVSqFYOPH8r9w=; b=tl62iCTSGGUzptMrZBT3jn2pI8pZCqeKaxunc+/i74OXDgPXysEIIL3VcfsiVdEHs+ rQT3E/me6WtAVRul6P2KR9AG3K/4kcVUxeRTCP1w7CyGhhimBm9BaJtUU7q09JAbPx6x NESQuQcPJkUaRY5OOBccR/ym/and1Fbey8QKCWwB3q6Y2TEz5GN1he+57nuDLWS2Jk9d SH8jGTqs5RZWp+zeUB6rDwtkBSXOuqk4m87KDJiiYkhyZFlF4AzEX+HLZu1uEa9hEDfL roA02KRkT/faqSBy0waKOwl+uXdHjtCVBxiJNwagRHAm1YobZkuv91JzU/TRWcUM09AM EFRw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=mgD3Cyxxudgq1gSLJurDa9ndROZwZFFVSqFYOPH8r9w=; b=GQcDlNUCveViti5vA3raNIbZ5aiJ19Bw2vldH09Vx8yPATVpDP6vYsORvv71CoTvT3 lGdqcVua8CujpynPDqe0lK8djK5XIL/gVJLkTTEUR80bjyD/wHLid7uRln3J74OIjefu NyahNJPApl7oqbIqjmfOCBFWrXwL0sNu7VCJzBH7SXW7hq/iCNQEDulQnVNbPCyoWaKV CciSNnIsosda3yPYIm/DEZ8sbtkD0eY+oLnggDm0mp3aSWNoAjA4wcXrXEijtx4OsQiv 8/kbqSyhOFRATlKiSvloxfYhdvnFqyVgmPT96OyqNg9F1lejU5QPYatPcgbNHK950hmK Az/g== X-Gm-Message-State: AOAM5318md/a2Cx51u4eGO6MaZRHhz6Ed14lVBTJHA26Px2+jvi3792g M6j01TTzyJZadGyvR64WJ46A3w== X-Google-Smtp-Source: ABdhPJzBPYsFnpalDMHcESuRyOdO6Ck/g/44YziuooFWmtHxb45HdNhMQeUc6UVWveNjMR9hbE/HCA== X-Received: by 2002:ad4:5506:: with SMTP id az6mr2984603qvb.8.1631115478998; Wed, 08 Sep 2021 08:37:58 -0700 (PDT) Received: from [192.168.1.10] (c-24-98-254-8.hsd1.ga.comcast.net. [24.98.254.8]) by smtp.gmail.com with ESMTPSA id n20sm1971682qkk.135.2021.09.08.08.37.57 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 08 Sep 2021 08:37:57 -0700 (PDT) Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.7\)) In-Reply-To: <46f2e842-8608-0622-f1c1-3eb746658c84@gmail.com> Date: Wed, 8 Sep 2021 11:37:56 -0400 Cc: internals@lists.php.net Content-Transfer-Encoding: quoted-printable Message-ID: References: <46f2e842-8608-0622-f1c1-3eb746658c84@gmail.com> To: Rowan Tommins X-Mailer: Apple Mail (2.3608.120.23.2.7) Subject: Re: [PHP-DEV] Alias stdClass to DynamicObject? From: mike@newclarity.net (Mike Schinkel) > On Sep 8, 2021, at 5:44 AM, Rowan Tommins = 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 >=20 > 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 =3D=3D=3D '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' =3D=3D=3D 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... =3D=3D=3D=3D=3D=3D=3D=3D 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.=20 Further, although the expression style of `(object)['prop' =3D> = '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. =20= 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 =3D (object)array( "foo" =3D> 1, "bar" =3D> "hello", "baz" =3D> true, );o We could do this instead: $obj =3D 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 =3D 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 =3D 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 =3D { 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.=20 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? >=20 > 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.=20 > 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: >=20 > $obj =3D 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 =3D=3D= =3D 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? >=20 > 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. =20 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.