首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PHP类型转换-好还是不好?

问PHP类型转换-好还是不好?
EN

Stack Overflow用户
提问于 2010-09-12 23:05:31
回答 5查看 4.4K关注 0票数 12

在用C和Java做了一些工作之后,我对PHP中的狂野西部法则越来越感到恼火。我真正觉得PHP缺少的是严格的数据类型。string('0') == (int)0 == (boolean)false就是一个例子。

您不能依赖函数返回的数据类型。您既不能强制函数的参数为特定类型,这可能会导致不严格的比较,从而导致一些意外的事情。一切都可以处理,但它仍然为意想不到的bug敞开大门。

对接收到的方法参数进行类型转换是一种好的做法还是坏的做法?那么,对回报进行类型转换好吗?

即

代码语言:javascript
复制
public function doo($foo, $bar) {
   $foo = (int)$foo;
   $bar = (float)$bar;
   $result = $bar + $foo;
   return (array)$result;
}

这个例子很愚蠢,我还没有测试过它,但我想每个人都明白这个想法。除了让不知道数据类型的人使用PHP之外,PHP之神还有什么理由可以随心所欲地转换数据类型?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-09-13 06:27:21

不管是好是坏,松散类型就是“ PHP Way"。许多内置代码和大多数语言构造都将在您提供的任何类型上操作--在幕后静默地(通常是危险地)转换它们,以使它们(某种程度上)适合在一起。

我自己有Java/C/C++背景,PHP的松散类型模型一直让我感到沮丧。但这些年来,我发现,如果我必须写PHP,我可以通过拥抱PHP的“松散”来做得更好(即更干净、更安全、更可测试的代码),而不是对抗它;因此,我最终成为了一只更快乐的猴子。

强制转换确实是我的技术的基础--而且(IMHO)这是始终如一地构建干净、可读的PHP代码的唯一方法,这些代码能够以一种易于理解、可测试、确定性的方式处理混合类型的参数。

主要的一点(您也清楚地理解)是,在PHP中,您不能简单地假设参数是您期望的类型。这样做可能会产生严重的后果,在你的应用程序投入生产之前,你不太可能捕捉到这些后果。

要说明这一点,请执行以下操作:

代码语言:javascript
复制
<?php

function displayRoomCount( $numBoys, $numGirls ) {
  // we'll assume both args are int

  // check boundary conditions
  if( ($numBoys < 0) || ($numGirls < 0) ) throw new Exception('argument out of range');

  // perform the specified logic
  $total = $numBoys + $numGirls;
  print( "{$total} people: {$numBoys} boys, and {$numGirls} girls \n" );
}

displayRoomCount(0, 0);   // (ok) prints: "0 people: 0 boys, and 0 girls" 

displayRoomCount(-10, 20);  // (ok) throws an exception

displayRoomCount("asdf", 10);  // (wrong!) prints: "10 people: asdf boys, and 10 girls"

解决此问题的一种方法是限制函数可以接受的类型,在检测到无效类型时引发异常。其他人已经提到了这种方法。它很适合我的Java/C/C++美学,我在PHP中使用这种方法已经有很多年了。简而言之,它没有什么问题,但它确实与“PHP方式”背道而驰,一段时间后,它开始感觉像是在上游游泳。

作为另一种选择,强制转换提供了一种简单明了的方法来确保函数对所有可能的输入都是确定性的,而不必编写特定的逻辑来处理每种不同的类型。

使用强制转换,我们的示例现在变成:

代码语言:javascript
复制
<?php

function displayRoomCount( $numBoys, $numGirls ) {
  // we cast to ensure that we have the types we expect
  $numBoys = (int)$numBoys;
  $numGirls = (int)$numGirls;

  // check boundary conditions
  if( ($numBoys < 0) || ($numGirls < 0) ) throw new Exception('argument out of range');

  // perform the specified logic
  $total = $numBoys + $numGirls;
  print( "{$total} people: {$numBoys} boys, and {$numGirls} girls \n" );
}

displayRoomCount("asdf", 10);  // (ok now!) prints: "10 people: 0 boys, and 10 girls"

该函数现在的行为与预期一致。实际上,很容易说明函数的行为现在已经针对所有可能的输入进行了很好的定义。这是因为强制转换操作对于所有可能的输入都是定义良好的;强制转换确保我们总是处理整数;而函数的其余部分被编写为对于所有可能的整数都是定义良好的。

Rules for type-casting in PHP are documented here,(参见页面中段的特定类型链接-例如:“转换为整数”)。

这种方法还有一个额外的好处,即函数现在将以与其他PHP内置和语言构造一致的方式运行。例如:

代码语言:javascript
复制
// assume $db_row read from a database of some sort
displayRoomCount( $db_row['boys'], $db_row['girls'] ); 

将工作得很好,尽管$db_row['boys']和$db_row['girls']实际上是包含数值的字符串。这与一般PHP开发人员(不了解C、C++或Java)期望它工作的方式是一致的。

至于转换返回值:这样做没有什么意义,除非您知道您有一个潜在的混合类型变量,并且您希望始终确保返回值是特定类型。这种情况通常发生在代码的中间点,而不是从函数返回的地方。

一个实际的例子:

代码语言:javascript
复制
<?php

function getParam( $name, $idx=0 ) {
  $name = (string)$name;
  $idx = (int)$idx;

  if($name==='') return null;
  if($idx<0) $idx=0;

  // $_REQUEST[$name] could be null, or string, or array
  // this depends on the web request that came in.  Our use of
  // the array cast here, lets us write generic logic to deal with them all
  //
  $param = (array)$_REQUEST[$name];

  if( count($param) <= $idx) return null;
  return $param[$idx];
}

// here, the cast is used to ensure that we always get a string
// even if "fullName" was missing from the request, the cast will convert
// the returned NULL value into an empty string.
$full_name = (string)getParam("fullName");

你明白了吧。

有几个需要注意的问题

  • PHP的强制转换机制不够智能,无法优化"no-op“强制转换。因此,强制转换总是会导致创建变量的副本。在大多数情况下,这不是问题,但如果你经常使用这种方法,你应该把它放在脑后。因此,强制转换可能会导致引用和大型数组出现意想不到的问题。
  • 在PHP Bug Report #50894中,一个太大(或太小)而不能表示为整数类型的整数,将自动表示为一个浮点型(如果需要,也可以表示为双精度型)。这意味着($big_int + $big_int)的结果实际上可以是一个浮点数,如果您将其强制转换为一个整数,则得到的结果将是胡言乱语。因此,如果您正在构建需要对大整数进行运算的函数,则应牢记这一点,并可能考虑其他方法。

很抱歉这篇文章很长,但这是一个我已经深入考虑的话题,这些年来,我积累了相当多的关于它的知识(和观点)。把它放在这里,我希望有人会发现它是有帮助的。

票数 23
EN

Stack Overflow用户

发布于 2010-09-12 23:25:54

PHP的下一个版本(可能是5.4) will support scalar type hinting in arguments。

但除此之外:动态类型转换确实不是你应该讨厌和避免的东西。大多数情况下,它会像预期的那样工作。如果没有,通过检查某种类型的is_*来修复它,使用严格的比较,...,...

票数 4
EN

Stack Overflow用户

发布于 2010-09-12 23:08:33

您可以对复杂类型使用type hinting。如果需要比较值+类型,可以使用"===“进行比较。

代码语言:javascript
复制
(0 === false) => results in false
(0 == false) => results in true

此外,您还编写了return (array)$result;,这没有任何意义。如果您希望返回类型是一个数组,那么在这种情况下您需要的是return array($result)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3695295

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档