Hi Rowan,

On Thu, Mar 9, 2017 at 10:09 PM, Rowan Collins <rowan.coll...@gmail.com> wrote:
> On 08/03/2017 23:32, Andrey Andreev wrote:
>>
>> For example, a Cookie object may have the cookie attributes (domain,
>> path, etc.) as value objects, but they can easily be created from raw
>> strings, while other types would be ambiguous.
>> A similar effect could be desirable for HTTP headers.
>
>
> OK, now we have some concrete examples, thanks. I would say that in these
> cases, what you actually want is a much tighter contract: not just "can be
> converted to string", but "intended to be used in this context".
>

I know you're trying to help, but I keep reading this as "OK, now I
can try to invalidate your use case".

There's always an alternative solution. I only ask that our
alternatives here include a middle ground between the two extremes of
"accept pretty much everything" and "be as strict as possible".

> It fits with what I was saying before about "if you can't name it, maybe it
> isn't the right abstraction". In this case, you want to accept some
> particular value objects but not, say, Exceptions - which are as useless for
> your purpose as an integer, even though (string)$foo would work fine on
> both.
>

I can name it; the name is just ridiculously long/impractical because
__toString() is a special case unlike anything else in PHP.

> So you want objects that have promised to behave appropriately for this
> context; that could be as simple as:
>
> interface HTTPHeaderObject {
>     public function __toString();
> }
>
> ...with appropriate documentation that objects declaring that they implement
> this interface promise to behave in a specific way when cast to string. This
> is much clearer than detecting __toString(), which only promises "I can be
> cast to string" - the same promise that is made by all scalar values.
>

My argument is that while every scalar value may promise that it "can
be cast to string", the fact that you need to explicitly declare it
means that only __toString() can promise that it "can be useful as a
string" (context-dependent of course).

>
> In order to accept this or a string in a type hint, you need Union Types:
>
> function setHeaderValue(string|HTTPHeaderObject $value) { ...
>

I would love union types, but unfortunately:

- https://wiki.php.net/rfc/union_types was declined
- They only address parameter hints, and I also want runtime checks
- Would still leave a gap for me, as I (perhaps stubbornly) want to
treat __toString() objects as regular strings

Though, I can live with the extra function call if we have union types
as that would greatly reduce my needs related to that last point.

>
> For broader use, we could perhaps have named unions:
>
> type HTTPHeaderType = union(string, HTTPHeaderObject);
> if ( $value instanceOf HTTPHeaderType ) { ...
>

An excellent idea, indeed - I'd be a huge proponent of that.

>
> Meanwhile, of course, you can just use a boring old user-defined function:
>
> function is_valid_http_header_value($value) {
>     return is_string($value) || $value instanceOf HTTPHeaderObject;
>
> }
>

Yes, and I can already wrap is_string($var) || method_exists($var,
'__toString') in a function, even "override" the original is_string()
with my version, in a namespace. The point was to eliminate that
boilerplate code.

----------------

Obviously, I'm getting zero support on the idea and we're running
around in circles at this point, so I guess that's it from me here.

Cheers,
Andrey.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to