如何在PHP 7之前解决“必须是字符串的实例,字符串给定”?

时间:2010-11-05 03:53:17

标签: php types type-hinting

这是我的代码:

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

导致此错误:

  

捕获致命错误:传递给phpwtf()的参数1必须是字符串的实例,给定字符串

看到PHP在同一口气中识别并拒绝所需的类型,不仅仅是一点Orwellian。 有五盏灯,该死的。

PHP中字符串的类型提示相当于什么?奖励考虑答案,准确解释这里发生了什么。

9 个答案:

答案 0 :(得分:187)

在PHP 7之前type hinting只能用于强制对象和数组的类型。标量类型不是类型可约束的。在这种情况下,期望类string的对象,但是你给它一个(标量)string。错误消息可能很有趣,但它不应该开始工作。鉴于动态类型系统,这实际上会产生某种变态感。

您只能手动“输入提示”标量类型:

function foo($string) {
    if (!is_string($string)) {
        trigger_error('No, you fool!');
        return;
    }
    ...
}

答案 1 :(得分:20)

来自PHP's manual

  

类型提示只能是对象和数组(自PHP 5.1以来)类型。不支持使用int和string的传统类型提示。

所以你拥有它。错误信息实际上没有用,我告诉你。

** 2017年编辑**

PHP7引入了更多的函数数据类型声明,上述链接已移至Function arguments : Type declarations。从该页面:

  

有效类型

     
      
  • 类/接口名称:参数必须是给定类或接口名称的实例。 (自PHP 5.0.0起)
  •   
  • self :参数必须是与定义方法的类相同的实例。这只能用于类和实例方法。 (自PHP 5.0.0起)
  •   
  • 数组:参数必须是数组。 (自PHP 5.1.0起)   callable参数必须是有效的可调用对象。 PHP 5.4.0
  •   
  • bool :参数必须是布尔值。 (自PHP 7.0.0起)
  •   
  • float :参数必须是浮点数。 (自PHP 7.0.0起)
  •   
  • int :参数必须是整数。 (自PHP 7.0.0起)
  •   
  • string :参数必须是字符串。 (自PHP 7.0.0起)
  •   
  • iterable :参数必须是数组或Traversable的instanceof。 (自PHP 7.1.0起)
  •   
     

警告

     

不支持上述标量类型的别名。相反,它们被视为类或接口名称。例如,使用boolean作为参数或返回类型将需要一个参数或返回值,该值是类或接口boolean的实例,而不是bool类型:

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

以上示例将输出:

 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

最后一个警告对于理解错误“参数必须是字符串类型,字符串给出”实际上很重要;由于大多数只允许类/接口名称作为参数类型,PHP试图找到一个类名“string”,但找不到任何因为它是一个基本类型,因此失败了这个尴尬的错误。

答案 2 :(得分:8)

PHP允许“提示”提供指定对象的类。根据PHP手册,“类型提示只能是对象和数组(自PHP 5.1以来)类型。不支持使用int和string的传统类型提示。”错误令人困惑,因为您选择“字符串” - 将“myClass”放在其位置并且错误将以不同方式读取:“传递给phpwtf()的参数1必须是myClass的实例,字符串给出”

答案 3 :(得分:3)

正如其他人已经说过的,类型提示目前仅适用于对象类型。但我认为您触发的特定错误可能是准备即将发生的字符串类型SplString

理论上它的行为类似于字符串,但由于它是一个对象,因此会传递对象类型验证。不幸的是,它还没有在PHP 5.3中,可能会在5.4中出现,所以没有对此进行测试。

答案 4 :(得分:2)

从PHP 7.0开始,类型声明允许标量类型,因此现在可以使用这些类型:selfarraycallableboolfloatintstring。前三个在PHP 5中可用,但最后四个在PHP 7中是新的。如果您使用其他任何内容(例如integerboolean)将被解释为类名。

See the PHP manual for more information

答案 5 :(得分:0)

从Laravel Controller调用函数到PHP文件时出现此错误。

几个小时后,我发现了问题:我在静态函数中使用 $ this

答案 6 :(得分:0)

(最初由leepowers在他的问题中发布)

错误信息令人困惑,其中一个重要原因是:

原始类型名称未在PHP中保留

以下是所有有效的类声明:

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

我的错误在于认为错误消息仅指字符串基元类型 - 单词'instance'应该让我暂停。举例说明:

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')]);

输出:

  

$ s1 - 原始字符串?是的 - 字符串实例?无

     

$ s2 - 原始字符串?没有 - 字符串实例?是

在PHP中,string可能是string,除非它实际上是string。与任何使用隐式类型转换的语言一样,上下文就是一切。

答案 7 :(得分:-1)

我认为对内部块上的php进行类型转换,PHP上的字符串不是我所知道的对象:

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

答案 8 :(得分:-1)

也许不安全而且漂亮,但如果你必须:

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"));