Stringy icon indicating copy to clipboard operation
Stringy copied to clipboard

PHP does not recognize Stringy as string

Open apapsch opened this issue 8 years ago • 3 comments

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:

  1. Do explicit type conversion everywhere. But then you litter your code and possibly copy strings when you could pass them by reference.
  2. Limit Stringy usage. But then you don't have the nice API and don't get strings passed by reference most of the time.
  3. 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.

apapsch avatar Oct 05 '17 15:10 apapsch

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.

ArchitectNate avatar Oct 06 '17 18:10 ArchitectNate

That's doable, although not feasable for third party code. It might be worth pursuing this extension of is_string in PHP core, WDYT?

apapsch avatar Oct 09 '17 08:10 apapsch

Slightly related:

  • https://wiki.php.net/rfc/stringable
  • https://github.com/symfony/polyfill/blob/main/src/Php80/Resources/stubs/Stringable.php

Sweetchuck avatar Jan 02 '22 14:01 Sweetchuck