Re: [RFC] [Discussion] DOM HTML5 parsing and serialization support
| From: | Niels Dossche | Date: | Thu, 21 Sep 2023 18:01:56 +0000 |
| Subject: | Re: [RFC] [Discussion] DOM HTML5 parsing and serialization support | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-121117@lists.php.net to get a copy of this message | ||
Hi Stephen
On 20/09/2023 12:02, Stephen Reay wrote:
>
>
>> On 20 Sep 2023, at 03:03, Niels Dossche <dossche.niels@gmail.com> wrote:
>>
>> Hi Stephen
>>
>> On 19/09/2023 09:58, Stephen Reay wrote:
>>>
>>>
>>>> On 19 Sep 2023, at 14:30, Tim Düsterhus <tim@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