> Just to show the range of viewpoints on this, I'd like to mention my opinion
> that Stringable is a horrible feature, with an implementation that's
> completely inconsistent with the rest of the language, and no clear semantic
> purpose. If your contract is "the input must be usable as a string", then the
> obvious type to require is "string".
> I'm not saying my opinion is objectively right, or even held by a majority, I
> just wanted to provide a counterbalance of sorts.
I don't think it's without purpose... what it should be for is to allow
developers to make flexible APIs where they can type-hint string|Stringable and
the user of the API doesn't have to worry about it.
There are examples where complex data types (object, enums) can be
intelligently and reasonably cast to a string for more than simply "output"
purposes (e.g. print statements, log files and the like). Since we have
__toString() it makes sense to me to have an interface I can type against to
know that method is valid to call instead of hunting around for it with
method_exists() or other some such thing. See below for an example I pulled off
the top of my head with an ORM.
> >function fooThatWantsString(string|Stringable|UnitEnum $bar)
> I would have thought the more common use case would be the opposite: you want
> the function to be limited to a particular enum, but allow strings for
> backward compatibility, and have this:
> function fooThatTakesAnOption(FooOptionEnum|string $opt) {
> if ( is_string($opt) ) {
> $opt = FooOptionEnum::from($opt);
> }
> ...
> }
I think there's pretty meaningful evidence based on the engagement in the PR
(and the number of likes in that PR regarding specifically at least allowing
__toString() to be implemented) that your version of the mock API above and my
version don't have to be mutually exclusive things -- nor is one vs. the other
better or worse from a generic perspective. A composer package you pull into
your project won't know the Enum type you want to pass in, but it shouldn't be
hard for you to pass in a string enum if the API requires a string. There are
plenty of APIs out there in the wild right now buried in various composer
packages that expect a string but a string-backed enum might make sense.... I
haven't tested this directly but just as an offhand example consider something
like Laravel's Eloquent ORM:
$model->query()->where('enumColumn', '=', MyEnum::MYVALUE)->get();
It's possible that Laravel has already been smart enough to add the necessary
logic to look for UnitEnum here and resolve that to MyEnum::MYVALUE->value ,
but my argument is that it shouldn't have to try that hard. Nor should I have
to write MyEnum::MYVALUE->value in my query -- nor should any developer ever
have to think/worry about that for a string enum with a string parameter. As a
library developer when I write a method to be used by others in an entirely
unknown context, if my method takes a string input then I should be able to
hint string|Stringable and know I've given users of my library maximum
flexibility with basically no real effort on my part (other than a redundant
$foo = (string)$foo line. The fact this works 99% of the time (except,
strangely, string-backed enums) is the inconsistency I want to repair here.
As it seems to me there isn't a particularly strong argument for why we don't
allow __toString() , would anyone have a strong objection to getting an RFC
going to get this voted on? I didn't look closely at the original PR from the
"auto implement __toString()" for string-backed enums, but I think this might
literally be a one-liner just to enable enums to implement __toString() and the
rest can be tossed.
John