it-swarm.cn

在PHP中类型转换变量,这样做的实际原因是什么?

众所周知,PHP具有 弱类型输入 。对于那些不喜欢的人,PHP.net说:

PHP在变量声明中不需要(或不支持)显式类型定义。变量的类型由使用该变量的上下文确定。

喜欢它还是讨厌它,PHP即时地重铸变量。因此,以下代码是有效的:

$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)

PHP还允许您显式转换变量,如下所示:

$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"

太酷了……但是,对于我自己的一生,我无法想到这样做的实际原因。

我对支持Java的语言进行强类型输入没有问题。很好,我完全理解。另外,我知道-并充分了解函数参数- 类型提示 的用处。

上面的引用解释了我类型转换的问题。如果PHP可以交换类型-at-will],即使您已经force cast一个类型,它也可以交换类型;它可以- on-the-fly当您在操作中需要某种类型时,这将使以下内容有效:

$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"

那有什么意义呢?


举一个用户定义类型转换在PHP中有意义的世界的理论示例:

  1. 您强制转换变量$foo作为int(int)$foo
  2. 您尝试将字符串值存储在变量$foo
  3. PHP引发异常! ←那会很有意义。突然存在用户定义类型转换的原因!

PHP将根据需要进行切换的事实使用户定义类型转换的意义变得模糊。例如,以下两个代码示例是等效的:

// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

最初问这个问题一年后,猜猜谁发现自己在实际环境中使用类型转换?敬上。

要求是在网站上显示餐厅菜单的货币值。该站点的设计要求修剪尾随零,以便显示如下所示:

Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3

我发现这样做的最好方法就是将变量强制转换为浮点数:

$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;

PHP修剪浮点数的尾随零,然后将浮点数重铸为字符串以进行串联。

45
Stephen

在弱类型语言中,存在类型转换以消除类型化操作中的歧义,否则编译器/解释器将使用顺序或其他规则来假定要使用哪个操作。

通常,我会说PHP遵循这种模式,但是在我检查过的情况下,PHP在每种情况下都表现出违反直觉的行为。

在这些情况下,使用JavaScript作为比较语言。

字符串连接

显然,这在PHP中不是问题,因为有单独的字符串串联.)和加法(+)运算符。

的JavaScript
var a = 5;
var b = "10"
var incorrect = a + b; // "510"
var correct = a + Number(b); // 15

字符串比较

在计算机系统中,“ 5”通常大于“ 10”,因为它不会将其解释为数字。在PHP中并不是这样,即使都是字符串,PHP也会意识到它们是数字,因此不需要强制转换):

的JavaScript
console.log("5" > "10" ? "true" : "false"); // true
PHP
echo "5" > "10" ? "true" : "false";  // false!

功能签名输入

PHP对函数签名实施了基本的类型检查,但不幸的是,它是如此有缺陷,可能很少使用。

我以为我可能做错了,但是 文档中的注释 确认不能在PHP函数签名-中使用数组以外的内置类型错误消息具有误导性。

PHP
function testprint(string $a) {
    echo $a;
}

$test = 5;
testprint((string)5); // "Catchable fatal error: Argument 1 passed to testprint()
                      //  must be an instance of string, string given" WTF?

而且与我知道的任何其他语言不同,即使您使用它能够理解的类型,也无法将null传递给该参数(must be an instance of array, null given)。真蠢.

布尔解释

[Edit]:这是新的。我想到了另一种情况,逻辑又一次与JavaScript相反。

的JavaScript
console.log("0" ? "true" : "false"); // True, as expected. Non-empty string.
PHP
echo "0" ? "true" : "false"; // False! This one probably causes a lot of bugs.

因此,总而言之,我能想到的唯一有用的情况是...(鼓声)

类型截断

换句话说,当您拥有一种类型的值(例如字符串),并且想要将其解释为另一种类型(int),并且想要强制其成为该类型的有效值之一时:

$val = "test";
$val2 = "10";
$intval = (int)$val; // 0
$intval2 = (int)$val2; // 10
$boolval = (bool)$intval // false
$boolval2 = (bool)$intval2 // true
$props = (array)$myobject // associative array of $myobject's properties

我看不到什么向上转换(到包含更多值的类型)会真正使您受益。

因此,尽管我不同意您提议的类型使用(您本质上是在提出 静态类型 ,但由于含糊不清,只有将force-cast转换为类型,才会抛出该类型一个错误-这会引起混乱),我认为这是一个好问题,因为在PHP中,强制转换几乎没有用途。

32
Nicole

您正在混合使用弱/强和动态/静态类型的概念。

PHP是脆弱且动态的,但是您的问题在于动态类型的概念。这意味着变量没有类型,值没有。

“类型转换”是一种产生与原始类型不同的新值的表达式。它对变量没有任何作用(如果涉及)。

我经常键入强制转换值的一种情况是在数字SQL参数上。您应该清理/转义插入到SQL语句中的任何输入值,或者(更好)使用参数化查询。但是,如果您希望某个值必须是整数,则将其强制转换会容易得多。

考虑:

function get_by_id ($id) {
   $id = (int)$id;
   $q = "SELECT * FROM table WHERE id=$id LIMIT 1";
   ........
}

如果我省略第一行,$id是SQL注入的简单向量。强制转换确保它是无害的整数;任何插入某些SQL的尝试都只会导致查询id=0

15
Javier

我在PHP中进行类型转换的一种用途是:

我正在开发一个Android应用,该应用向服务器上的PHP脚本发出http请求,以从数据库中检索数据。该脚本以PHP对象(或关联数组)的形式存储数据,并作为JSON对象返回到应用程序。如果没有类型转换,我将收到以下内容:

{ "user" : { "id" : "1", "name" : "Bob" } }

但是,在将PHP对象存储到用户ID时,使用PHP类型在用户ID上强制转换(int),我将其返回给应用程序:

{ "user" : { "id" : 1, "name" : "Bob" } }

然后,当在应用程序中解析JSON对象时,它使我不必将id解析为Integer!

看,非常有用。

4
Ryan

一个示例是带有__toString方法的对象:$str = $obj->__toString();$str = (string) $obj;。第二种输入少得多,而标点符号是多余的东西,这需要更长的时间才能输入。我也认为它更具可读性,尽管其他人可能不同意。

另一个方法是制作一个单元素数组:array($item); vs (array) $item;。这会将任何标量类型(整数,资源等)放入数组中。
替代地,如果$item是一个对象,其属性将成为其值的键。但是,我确实认为object-> array转换有点奇怪:private和protected属性是数组的一部分,并已重命名。引用 PHP文档 :私有变量的类名放在变量名的前面;受保护的变量在变量名前带有“ *”。

另一个用途是将GET/POST数据转换为数据库的适当类型。 MySQL可以自行处理,但我认为符合ANSI标准的服务器可能会拒绝数据。我只提到数据库的原因是,在大多数其他情况下,数据将在某个时候根据其类型在数据库上执行操作(即,通常对int/floats进行计算等)。

3
Alan Pearce

它也可以用作一种快速而肮脏的方法,以确保不受信任的数据不会破坏某些内容,例如,如果使用具有废话验证且只能接受数字的远程服务。

$amount = (float) $_POST['amount'];

if( $amount > 0 ){
    $remoteService->doacalculationwithanumber( $amount );    
}

显然,这是有缺陷的,并且也可以由if语句中的比较运算符隐式处理,但有助于确保您确切地知道代码在做什么。

0
Gruffputs

该脚本:

$tags = _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}

script.php?tags[]=one可以正常运行,但script.php?tags=one则不能运行,因为_GET['tags']在第一种情况下返回数组,但在第二种情况下不返回数组。由于脚本是为期望数组而编写的(并且您对发送到脚本的查询字符串的控制较少),可以通过适当地转换_GET的结果来解决问题:

$tags = (array) _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}
0
beldaz