在用C和Java进行了一些工作之后,PHP的狂野西部法律使我越来越烦恼。我真正感到PHP缺乏的是严格的数据类型。一个例子就是string('0')==(int)0 ==(boolean)false。
您不能依赖于函数返回的数据类型是什么。您都不能强迫函数的参数为特定类型,否则可能导致比较严格的比较,从而导致意外情况。一切都可以解决,但仍然会出现意外错误。
类型转换为方法接收的参数是好是坏做法?键入回报是否很好?
IE浏览器
public function doo($foo, $bar) {
$foo = (int)$foo;
$bar = (float)$bar;
$result = $bar + $foo;
return (array)$result;
}
这个例子很愚蠢,我还没有测试过,但是我想每个人都明白。除了让不知道数据类型的人使用PHP之外,PHP神是否有任何理由按他的意愿转换数据类型?
参考方案
不管是好是坏,松散类型都是“ PHP方式”。许多内置函数和大多数语言构造都可以在您给它们提供的任何类型上运行-静默地(通常是危险地)将它们抛到幕后以使事物(某种)融为一体。
PHP本身来自Java / C / C ++背景,它的松散模型始终使我感到沮丧。但是这些年来,我发现,如果我必须编写PHP,我可以通过拥抱PHP的“宽松性”而不是与之抗争来做得更好(即更干净,更安全,更具可测试性的代码)。因此,我最终得到了一只更快乐的猴子。
强制转换实际上是我的技术的基础-(IMHO)这是始终如一地构建清晰易读的PHP代码的唯一方法,该代码以一种易于理解,可测试,确定性的方式处理混合类型的参数。
要点(您也清楚地了解了)是,在PHP中,您不能简单地假设参数是您期望的类型。这样做可能会导致严重的后果,直到您的应用程序正式投入生产后,您才有可能被抓住。
为了说明这一点:
<?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方式”背道而驰,过了一会儿,就开始感觉像是在上游游泳。
作为一种替代方法,强制转换提供了一种简单干净的方法来确保该函数对于所有可能的输入都具有确定性,而不必编写特定的逻辑来处理每种不同的类型。
使用强制转换,我们的示例现在变为:
<?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内置组件和语言构造一致的方式运行。例如:
// 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)期望其工作的方式一致。
至于强制转换返回值:这样做没有什么意义,除非您知道自己有一个潜在的混合类型变量,并且要始终确保返回值是特定类型。这种情况通常发生在代码的中间点,而不是从函数返回的点。
一个实际的例子:
<?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的强制转换机制不够智能,无法优化“无操作”强制转换。因此,强制转换始终会导致生成变量的副本。在大多数情况下,这不是问题,但是如果您定期使用此方法,则应将其放在脑海中。因此,强制转换会导致引用和大型数组出现意外问题。有关更多详细信息,请参见PHP Bug Report #50894。
在php中,太大(或太小)以至于不能表示为整数类型的整数将自动表示为浮点数(如果需要,则为双精度数)。这意味着($big_int + $big_int)
的结果实际上可以是浮点数,并且如果将其强制转换为int,则结果数将是乱码。因此,如果要构建需要对大量整数进行运算的函数,则应牢记这一点,并可能考虑采用其他方法。
抱歉,很长的帖子,但这是我已经深入考虑的话题,并且多年来,我已经积累了很多关于它的知识(和见解)。通过在这里发布,希望有人会有所帮助。
PHP:将数组值加在一起 - php我相信这比标题听起来要难一些,但我可能完全错了。我有一个像这样的数组:[["londrina",15],["cascavel",34],["londrina",23],['tiradentes',34],['tiradentes',21]] 我希望能够采用通用…
PHP-将日期插入日期时间字段 - php我已在数据库中使用datetime字段存储日期,使用PHP将“今天的日期”插入该字段的正确方法是什么?干杯, 参考方案 我认为您可以使用php date()函数
PHP-如何获取类的成员函数列表? - php如果我知道班级的名字。有没有办法知道类的成员函数列表? 参考方案 get_class_methods()是你的朋友
PHP strtotime困境 - php有人可以解释为什么这在我的服务器上输出为true吗?date_default_timezone_set('Europe/Bucharest'); var_dump( strtotime('29.03.2015 03:00', time()) === strtotime('29.03.2015 04:00…
PHP-全局变量的性能和内存问题 - php假设情况:我在php中运行一个复杂的站点,并且我使用了很多全局变量。我可以将变量存储在现有的全局范围内,例如$_REQUEST['userInfo'],$_REQUEST['foo']和$_REQUEST['bar']等,然后将许多不同的内容放入请求范围内(这将是适当的用法,因为这些数据指的是要求自…