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


217

这是我的代码:

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

导致此错误:

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

看到PHP能够一口气识别并拒绝所需的类型,这不仅仅是一个Orwellian。该死的,有五个灯。

PHP中字符串的类型提示等效于什么?对答案的额外考虑,可以准确解释这里发生的情况。


5
好吧,那是因为您做错了。首先,您的代码不起作用。在PHP文档中阅读杂耍类型。PHP是动态类型和弱类型。您可以使用(string)将参数转换为string(尽管仅在函数体中),但是只能像在代码片段中那样提示对象和数组。
理查德·诺普

7
问题是您犯了一个小错误。有四个灯!
CJ丹尼斯

@戈登,我在5.6上进行了测试。仍然没有运气。
Pacerier,2015年

@Pacerier请关注wiki.php.net/rfc了解最新动态。
Gordon

3
显然,根据消息来源,标量类型提示(如直觉上希望OP属于上述内容)终于在RFC下被批准用于PHP * 7 * 。显然,批准的RFC还提供了语法糖,用于类型检查返回值以及参数(参数)。即将过去很长时间了。
SeldomNeedy

Answers:


204

在PHP 7之前,类型提示只能用于强制对象和数组的类型。标量类型不是类型隐含的。在这种情况下,应该使用该类的对象string,但是您要给它一个(标量)string。该错误消息可能很有趣,但是一开始它不起作用。给定动态键入系统,这实际上具有某种变态的意义。

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

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

1
@deceze,是否存在用于反向类型提示的语法?如什么,但阵列。
Pacerier,2015年

@Pacerier不,没有。
deceze

4
这个答案不适用于PHP 7
Jose Nobile 2015年

24

PHP的手册

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

这样就可以了。错误消息并没有真正的帮助,但是我给了你。

** 2017编辑**

PHP7引入了更多的函数数据类型声明,并且前面提到的链接已移至Function参数:Type声明。从该页面:

有效类型

  • 类/接口名称:参数必须是给定类或接口名称的实例。(自PHP 5.0.0起)
  • self:参数必须是与定义方法的类相同的实例。这只能用于类和实例方法。(自PHP 5.0.0起)
  • array:参数必须是一个数组。(自PHP 5.1.0起)callable该参数必须是有效的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的数组或实例。(自PHP 7.1.0起)

警告

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

<?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”,但由于它是原始类型而找不到任何名称,因此由于此尴尬错误而失败。


8

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


3

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

从理论上讲,它的行为类似于字符串,但是由于它是一个对象,因此将通过对象类型验证。不幸的是,它尚未在PHP 5.3中出现,可能会在5.4中出现,因此尚未对其进行测试。


2

随着PHP 7.0的类型声明允许标量类型,所以这些类型的,现在可供选择:selfarraycallableboolfloatintstring。前三个在PHP 5中可用,但后四个在PHP 7中是新增功能。如果您使用其他任何内容(例如integerboolean),则将其解释为类名。

有关更多信息,请参见PHP手册


0

可能不安全漂亮,但是如果您必须:

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

5
我仍然可以创建一个new string(array(1,2,3))
Jimmy T.

0

从Laravel控制器向PHP文件调用函数时出现此错误。

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


Using $this when not in object context确实是一条神秘的讯息。
本·弗兰森

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中,可以将a string设为string例外,而实际上却是string。与使用隐式类型转换的任何语言一样,上下文就是一切。


-1

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

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

2
您可以在函数内添加is_string()验证,以防止将其他值传递给该函数。
subosito

1
(string) $s如果$s是无法转换为字符串的对象(可能未__toString()实现任何方法),则可能会引发错误,所以它不那么容易
Yanick Rochon 2010年

是的,Yanick,您是对的。但是我们不能强迫所有输入都是字符串对吗?这就是为什么异常起作用。我们可以将各种验证结合起来,并为剩下的捕获异常;)
subosito 2010年

我只是说避免将某些变量转换为字符串而不首先检查是否可以转换该变量,主要是因为捕获异常的代价很高,并且会导致不良的设计模式/编码习惯。
Yanick Rochon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.