228

Here is my code:

function phpwtf(string $s) {
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");

Which results in this error:

Catchable fatal error: Argument 1 passed to phpwtf() must be an instance of string, string given

It's more than a little Orwellian to see PHP recognize and reject the desired type in the same breath. There are five lights, damn it.

What is the equivalent of type hinting for strings in PHP? Bonus consideration to the answer that explains exactly what is going on here.

5
  • 5
    Well, that is because you are doing it wrong. Your code is not supposed to work, to begin with. Read up on type juggling in PHP docs. PHP is dynamic typed and weak typed. You can use (string) to cast an argument to string (only in function body though) but you can only hint objects and arrays like you do in your code snippet. Commented Nov 5, 2010 at 9:08
  • @Gordon, I tested on 5.6. Still no luck. Commented Apr 3, 2015 at 20:05
  • @Pacerier Please follow wiki.php.net/rfc for the latest developments. Commented Apr 4, 2015 at 7:51
  • 3
    Apparently, scalar type-hinting (as OP intuitively expected to be a thing above) has finally been approved under an RFC for PHP *7* according to source. The approved RFC apparently also provides syntactic sugar for type-checking return-values as well as parameters (arguments). It's been a long time in the coming. Commented Oct 28, 2015 at 1:01
  • Possible duplicate of Error when passing string into method with type hinting Commented Oct 13, 2017 at 10:35

9 Answers 9

217

Prior to PHP 7 type hinting can only be used to force the types of objects and arrays. Scalar types was not type-hintable. In this case an object of the class string is expected, but you're giving it a (scalar) string. The error message may be funny, but it's not supposed to work to begin with. Given the dynamic typing system, this actually makes some sort of perverted sense.

Your best bet is to upgrade the PHP version, because even PHP7 is long gone now.

In case it's impossible, you can simply remove that typehint altogether.

If you still want to check the parameter type, you can do it manually:

function foo($string) {
    if (!is_string($string)) {
        throw new RuntimeException(
            'Argument must be of type string '.gettype($type).' given'
        );
    }
    ...
}
Sign up to request clarification or add additional context in comments.

4 Comments

@deceze, Is there a syntax for reverse type hinting? E.g. anything but arrays.
@Pacerier No, there isn't.
This answer is not valid for PHP 7
@JoseNobile in PHP 7 this error doesn't exist. So, in a way - yes, this answer is not valid for PHP7 because such a problem doesn't exist in that version at all. So you shouldn't really care
29

From the PHP manual at the time of writing this answer:

Type Hints can only be of the object and array (since PHP 5.1) type. Traditional type hinting with int and string isn't supported.

So you have it. The error message is not really helpful, I give you that though.

** 2017 Edit **

PHP7 introduced more function data type declarations, and the aforementioned link has been moved to Function arguments : Type declarations. From that page :

Valid types

  • Class/interface name : The parameter must be an instanceof the given class or interface name. (since PHP 5.0.0)
  • self : The parameter must be an instanceof the same class as the one the method is defined on. This can only be used on class and instance methods. (since PHP 5.0.0)
  • array : The parameter must be an array. (since PHP 5.1.0)
  • callable : The parameter must be a valid callable. (since PHP 5.4.0)
  • bool : The parameter must be a boolean value. (since PHP 7.0.0)
  • float : The parameter must be a floating point number. (since PHP 7.0.0)
  • int : The parameter must be an integer. (since PHP 7.0.0)
  • string : The parameter must be a string. (since PHP 7.0.0)
  • iterable : The parameter must be either an array or an instanceof Traversable. (since PHP 7.1.0)

Warning

Aliases for the above scalar types are not supported. Instead, they are treated as class or interface names. For example, using boolean as a parameter or return type will require an argument or return value that is an instanceof the class or interface boolean, rather than of type bool:

<?php
  function test(boolean $param) {}
  test(true);
?>

The above example will output:

 Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of boolean, boolean given, called in - on line 1 and defined in -:1

The last warning is actually significant to understand the error "Argument must of type string, string given"; since mostly only class/interface names are allowed as argument type, PHP tries to locate a class name "string", but can't find any because it is a primitive type, thus fail with this awkward error.

Comments

8

PHP allows "hinting" where you supply a class to specify an object. According to the PHP manual, "Type Hints can only be of the object and array (since PHP 5.1) type. Traditional type hinting with int and string isn't supported." The error is confusing because of your choice of "string" - put "myClass" in its place and the error will read differently: "Argument 1 passed to phpwtf() must be an instance of myClass, string given"

Comments

3

As others have already said, type hinting currently only works for object types. But I think the particular error you've triggered might be in preparation of the upcoming string type SplString.

In theory it behaves like a string, but since it is an object would pass the object type verification. Unfortunately it's not yet in PHP 5.3, might come in 5.4, so haven't tested this.

Comments

2

As of PHP 7.0 type declarations allow scalar types, so these types are now available: self, array, callable, bool, float, int, string. The first three were available in PHP 5, but the last four are new in PHP 7. If you use anything else (e.g. integer or boolean) that will be interpreted as a class name.

See the PHP manual for more information.

Comments

0

I got this error when invoking a function from a Laravel Controller to a PHP file.

After a couple of hours, I found the problem: I was using $this from within a static function.

1 Comment

Using $this when not in object context is indeed a cryptic message.
0

(originally posted by leepowers in his question)

The error message is confusing for one big reason:

Primitive type names are not reserved in PHP

The following are all valid class declarations:

class string { }
class int { }
class float { }
class double { }

My mistake was in thinking that the error message was referring solely to the string primitive type - the word 'instance' should have given me pause. An example to illustrate further:

class string { }
$n = 1234;
$s1 = (string)$n;
$s2 = new string();
$a = array('no', 'yes');
printf("\$s1 - primitive string? %s - string instance? %s\n",
        $a[is_string($s1)], $a[is_a($s1, 'string')]);
printf("\$s2 - primitive string? %s - string instance? %s\n",
        $a[is_string($s2)], $a[is_a($s2, 'string')]);

Output:

$s1 - primitive string? yes - string instance? no

$s2 - primitive string? no - string instance? yes

In PHP it's possible for a string to be a string except when it's actually a string. As with any language that uses implicit type conversion, context is everything.

Comments

-1

I think typecasting on php on inside block, String on PHP is not object as I know:

<?php
function phpwtf($s) {
    $s = (string) $s;
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");

4 Comments

You can add is_string() validation inside your function to prevent other value passed to the function.
(string) $s may throw an error if $s is an object that cannot be cast into string (has no __toString() method implemented), so it's not as easy as that
Yes Yanick you're right. But we can't forced all of input to be string right? that's why exception comes to play. We can combine sort of validations and catch exception for the rest ;)
I'm just saying that casting some variable to string without checking first if the variable can be cast should be avoided, mainly because catching exceptions is costly and leads to bad design patterns / coding habbits.
-1

Maybe not safe and pretty but if you must:

class string
{
    private $Text;
    public function __construct($value)
    {
        $this->Text = $value;
    }

    public function __toString()
    {
        return $this->Text;
    }
}

function Test123(string $s)
{
    echo $s;
}

Test123(new string("Testing"));

1 Comment

I could still create a new string(array(1,2,3))

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.