PHP does not recognize Stringy as string
Please take a look at this constructor from https://github.com/lanthaler/IRI/blob/a04d4f923700dc5b4a19e1e105f978b50647efaa/IRI.php#L80
public function __construct($iri = null)
{
if (null === $iri) {
return;
} elseif (is_string($iri)) {
$this->parse($iri);
} elseif ($iri instanceof IRI) {
$this->scheme = $iri->scheme;
$this->userinfo = $iri->userinfo;
$this->host = $iri->host;
$this->port = $iri->port;
$this->path = $iri->path;
$this->query = $iri->query;
$this->fragment = $iri->fragment;
} else {
throw new \InvalidArgumentException(
'Expecting a string or an IRI, got ' .
(is_object($iri) ? get_class($iri) : gettype($iri))
);
}
}
I naively wrote this:
$foo = new Stringy('bar');
$baz = new IRI($foo);
and got that:
InvalidArgumentException: Expecting a string or an IRI, got Stringy\Stringy
The solution is explicit type conversion:
$baz = new IRI((string)$foo);
My naive approach was done under the impression that Stringy should act like a PHP string, even though it is an object. How would you approach this issue? I can imagine:
- Do explicit type conversion everywhere. But then you litter your code and possibly copy strings when you could pass them by reference.
- Limit Stringy usage. But then you don't have the nice API and don't get strings passed by reference most of the time.
- Do some magic in PHP core in order for code to treat string classes as strings without needing changes (i.e. no littering with
(string)). That could include an interface which is_string recognizes and returns true for. Also, an instance of the class implementing the interface would be treated as a PHP string most of the time, except when methods are invoked on the instance. And the string object would be passed by reference of course.
Approaches 1 and 2 seem like hacks, though they are in reach. Approach 3 is the best from user perspective but I don't know if it's viable. It might entail a ton of changes in PHP core.
Peter Barney has a decent solution, replace your is_string() calls with is_stringy() calls
http://php.net/manual/en/function.is-string.php#121637
<?php
// determine if the passed argument can be treated like a string.
function is_stringy($text) {
return (is_string($text) || (is_object($text) && method_exists($text, '__toString' ));
}
This won't solve TypeHinting, especially with strict typing.
That's doable, although not feasable for third party code. It might be worth pursuing this extension of is_string in PHP core, WDYT?
Slightly related:
- https://wiki.php.net/rfc/stringable
- https://github.com/symfony/polyfill/blob/main/src/Php80/Resources/stubs/Stringable.php