Hi Stephen On 20/09/2023 12:02, Stephen Reay wrote: > > >> On 20 Sep 2023, at 03:03, Niels Dossche <dossche.ni...@gmail.com> wrote: >> >> Hi Stephen >> >> On 19/09/2023 09:58, Stephen Reay wrote: >>> >>> >>>> On 19 Sep 2023, at 14:30, Tim Düsterhus <t...@bastelstu.be> wrote: >>>> >>>> Hi >>>> >>>> On 9/19/23 08:35, Stephen Reay wrote: >>>>> Regarding the private constructor: I understand the issue with the *old* >>>>> class being confusing - but your new class doesn't have that issue, >>>>> because there are no "loadXXX" methods: as you said, if you're loading an >>>>> existing document, you're forced to do it via the static factory methods. >>>>> With that change alone, there's zero risk of confusion in allowing direct >>>>> constructor calls, because once the object is instantiated there is no >>>>> subsequent way to load a document and inadvertently change the encoding. >>>>> Having a regular constructor and then one or more factory methods for >>>>> specific cases is already a concept in PHP (i.e. DateTime[Immutable]'s >>>>> `createFromXXX` as well as a constructor), and IMO needing to call a >>>>> factory method to get an "empty" document seems out of place in PHP - it >>>>> seems a bit like a Java-ism - using a factory, where one just isn't >>>>> required. >>>> >>>> I was one of the persons who discussed this updated API with Niels in >>>> private and looking up the discussion it was me who proposed making the >>>> constructor private and just providing named constructors. >>>> >>>> From the perspective of the user of the API, I like the symmetry between >>>> all the named constructors: >>>> >>>> Whenever I want to create a new document, I use one of the fromXyz() >>>> methods. And when I use those, I get exactly what it says on the tin. >>>> >>>> Making the regular constructor available for use would effectively make >>>> whatever that constructor does a special case / the default case. This >>>> makes sense for DateTimeImmutable, because the __construct() variant is >>>> likely much more often used than the various createFromXyz() variants. For >>>> the HtmlDocument I find it less obvious that creating an empty document >>>> would be the default case compared to loading an existing document from a >>>> file. >>>> >>>> We should probably rename the named constructors to include the "create" >>>> prefix for consistency with DTI though. >>>> >>>> Best regards >>>> Tim Düsterhus >>>> >>> >>> Hi Tim, >>> >>> >>> Thanks for providing context on where this idea came from. >>> >>> >>> The constructor + specialised factory methods pattern is not exactly new in >>> PHP (e.g. it took about 3 minutes to find multiple Symphony classes doing >>> this), and disabling the public constructor for purely cosmetic reasons >>> sounds like a very weird, and ironic choice to me, when the stated goal is >>> to make the API *less surprising* than the previous one. >>> >> >> Besides the points that have been mentioned by Tim and Larry, there's also >> the expectation of the programmer that migrates to the new classes to take >> into account. >> They're used to calling the constructor on the old class and calling a load >> method afterwards. >> As there is still a constructor, but no load method, this might be confusing >> for them. >> So in my opinion, disabling it makes it less surprising than the previous >> one. >> Also, just because Symfony does this doesn't mean it's automatically >> something we should follow. >> >>> >>> Cheers >>> >>> Stephen >> >> Kind regards >> Niels >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: https://www.php.net/unsub.php >> <https://www.php.net/unsub.php> > > Hi Niels, Larry > > To clarify my earlier message about having the factory methods on the > faux-interface - when I said meta programming that was probably the wrong > term to use, so I apologise for the confusion. > It's true that the *developer* needs to know the expected type of the string > being parsed. It's not true that the code directly invoking the 'fromString' > method necessarily needs to know - passing classnames as a string and calling > static methods on the string is also an established concept in PHP, which > works really well when the method being called is defined on a single > top-level class or interface. > A real world example I had in mind, is a Request (e.g. a curl request, or > some other http-fetching) class that can decode responses into native PHP > objects, with options for the callee to define the object type that's wanted; > with just the two provided classes there's already double the checks required > to know if the specified class name is one the library knows how to use. If a > hypothetical class to handle SVG, RSS, ODF (or any other specialised use of > XML) class uses the faux-interface from this RFC as it's base, there's no way > for the Request class to know that it can instantiate an instance from a > string, without falling back to method_exists() checks. >
You'd still have to know the signature, and what options it accepts and affect the parser to be able to use it in a meaningful way. Anyway, you can still do this use-case without a method_exists check or something alike by using union types for example. You'll likely still want to put some kind of limitations on, so limiting via type seems sensible. > > The only reason I mentioned the DateTime or Symphony classes at all, is to > highlight that people have been using classes with a regular constructor, and > one or more static factory methods, for years, and if there has been any > confusion about it thus far, it's not something I've ever heard complaints > about, nor seen efforts to address. > > > Calling arbitrarily named static methods "named constructors" doesn't really > make a convincing argument when someone suddenly realises that the names > should be something else halfway through the same conversation. That doesn't > mean there's something wrong specifically with having static factory methods > when they're needed, but that's my whole point: the *default* way to > instantiate an object in PHP is through its constructor, and classes that > *don't* provide a public constructor are *much* less common, usually with an > obvious reason why (e.g. they're a singleton, or they're objects migrated > from resource handles). > > > I've had enough of these conversations to realise that you've made a decision > and you're sticking to it, regardless of what I might write (well except for > changing the completely arbitrary names, I guess), so I won't continue trying > to make my point to you. > > Please at least do one thing though: make it *clear* in the RFC that the > public constructor is removed because ... well I don't know, pick one of the > reasons you've thrown up I guess. But right now the only reason even vaguely > mentioned in the RFC is that it prevents the "changed encoding" issue, but it > doesn't do that, the lack of a load method achieves that, and IMO the lack of > a regular constructor is a significant enough change from most PHP classes, > that people should be aware of that when reading and voting on your proposal. > I will list the reasons more clearly in the RFC. > > > Cheers > > > Stephen Kind regards Niels -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php