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