奇怪的php_您可能不知道的3个奇怪PHP事实

奇怪的php

There is no doubt: PHP is an easy, flexible, and forgiving language. But it can also exhibit some surprising behavior. In this article I’ll present some “strange facts” and explain why PHP gives the results it does.

毫无疑问:PHP是一种简单,灵活且宽容的语言。 但是它也可能表现出一些令人惊讶的行为。 在本文中,我将介绍一些“奇怪的事实”,并解释PHP为什么给出其结果。

浮点精度 (Floating Point Imprecision)

Most of you probably know that floating-point numbers cannot really represent all real numbers. Besides, some operations between two well represented numbers can lead to surprising situations. This is because the finite precision with which computers represent numbers and so it affects not just PHP but all the programming languages. Inaccuracies in floating point problems have been given programmers headaches from the beginning of the discipline.

你们中的大多数人可能知道浮点数不能真正代表所有实数。 此外,两个很好表示的数字之间的某些运算可能会导致令人惊讶的情况。 这是因为计算机代表数字的有限精度,因此它不仅影响PHP,还影响所有编程语言。 从该学科的开始,浮点问题的不准确性就已使程序员头痛。

About this question many words have been said, but one of the most important articles written is What Every Computer Scientist Should Know About Floating-Point Arithmetic. If you’ve never had a chance to read it, I strongly suggest you do so.

关于这个问题,已经说了很多词,但是写的最重要的文章之一是每位计算机科学家应该了解的浮点运算法则 。 如果您从未有过阅读的机会,强烈建议您阅读。

Let’s look at this very small snippet:

让我们看一下这个非常小的片段:

<?php
echo (int) ((0.1 + 0.7) * 10);

What do you think will be the result? If you guessed 8, you’d be wrong… I’m sorry, you lost the prize! This code will actually print 7! For those who have a Zend Certification, this example is already known. Infact, you can find it in Zend PHP 5 Certification Study Guide.

您认为结果如何? 如果您猜到了8,那您错了……对不起,您输了奖! 此代码实际上将打印7! 对于拥有Zend认证的人,此示例是已知的。 实际上,您可以在《 Zend PHP 5认证研究指南》中找到它。

Now let’s see why this happens. The first operation executed is:

现在让我们看看为什么会这样。 执行的第一个操作是:

0.1 + 0.7 // result is 0.79999999999

0.1 + 0.7 // result is 0.79999999999

The result of the arithmetic expression is stored internally as 0.7999999, not 0.8 due to the precision issue, and this is where the problem starts.

由于精度问题,算术表达式的结果在内部存储为0.7999999,而不是0.8,这是问题开始的地方。

The second operation executed is:

执行的第二个操作是:

0.79999999 * 10 = 7.999999999

0.79999999 * 10 = 7.999999999

This operation works well but preserves the error.

此操作效果很好,但保留了错误。

The third and last operation executed is:

执行的第三个也是最后一个操作是:

(int) 7.9999999 // result is 7

(int) 7.9999999 // result is 7

The expression makes use of an explicit cast. When a value is convert to int, PHP truncates the decimal portion of the number which makes the result 7.

该表达式使用显式强制转换。 当将值转换为int ,PHP将截断数字的小数部分,从而得出结果7。

There are two interesting things to note here:

这里有两个有趣的事情要注意:

  • If you cast the number to float instead of int, or if you don’t cast at all, you’ll get 8 as result as you expected.

    如果将数字floatfloat而不是int ,或者完全不强制转换,则结果将为预期的8。

  • Although the CPU doesn’t know, and we actually we got this error due to its imprecisions, it’s working accordingly to the mathematics paradox that asserts 0.999… is equal to 1.

    尽管CPU不知道,但实际上由于错误的原因而出现了此错误,但它的工作是针对断言0.999…等于1的数学悖论。

To conclude this point, I’d like to cite the Zend PHP 5 Certification Study Guide Second Edition:

总结一下,我想引用《 Zend PHP 5认证学习指南第二版》

Whenever the precision of your calculation is a relevant factor to the proper functioning of your application, you should consider using a (sic) the arbitrary precision functions provided by the BCMath extension (you can search for it in your copy of the PHP manual) instead of PHP’s built-in data types.

每当计算精度与应用程序正常运行相关时,就应该考虑使用(原文如此)BCMath扩展提供的任意精度函数(您可以在PHP手册的副本中进行搜索) PHP的内置数据类型。

PHP如何“递增”字符串 (How PHP “Increments” Strings)

During our everyday work we write instructions that perform incrementing/decrementing operations like these:

在我们的日常工作中,我们编写指令来执行递增/递减操作,如下所示:

<?php
$a = 5;
$b = 6;
$a++;
++$b;

Everyone easily understands what’s going on with those statements. But given the following statements, guess what will be the output:

每个人都容易理解这些语句的作用。 但是,考虑到以下语句,请猜测输出是什么:

<?php
$a = 1;
$b = 3;
echo $a++ + $b;
echo $a + ++$b;
echo ++$a + $b++;

Did you write down your answers? Good. Let’s check ’em all.

你写下答案了吗? 好。 让我们检查一下。

4
6
7

Not too difficult, right? Now let’s raise the bar a little. Have you ever tried to increment strings? Try to guess what the output will be for the following:

不太困难吧? 现在让我们提高一点。 您是否尝试过增加字符串? 尝试猜测以下内容的输出:

<?php
$a = 'fact_2';
echo ++$a;

$a = '2nd_fact';
echo ++$a;

$a = 'a_fact';
echo ++$a;

$a = 'a_fact?';
echo ++$a;

It’s not so easy this time, is it. Let’s uncover the answers.

这次不是那么容易,是吧。 让我们找出答案。

fact_3
2nd_facu
a_facu
a_fact?

Surprised? Using an increment operator on a string that ends with a number has the effect of increasing the letter (the one following it in the alphabet, e.g. t -> u). Regardless if the string starts with digits or not, the last character is changed. But there is no effect if the string ends with a non-alphanumeric character.

惊讶吗 在以数字结尾的字符串上使用增量运算符具有增加字母(字母后面的字母,例如t-> u)的效果。 不管字符串是否以数字开头,最后一个字符都会更改。 但是,如果字符串以非字母数字字符结尾,则没有任何效果。

This is well documented by the official documentation about the incrementing/decrementing operators but most of you may not have read it because you probably thought nothing special was there. I must admit I thought the same until a short time ago.

关于递增/递减运算符的官方文档对此进行了充分的记录,但是您中的大多数人可能没有读过它,因为您可能认为那里没有什么特别的。 我必须承认,直到不久前,我还是这么认为。

PHP follows Perl’s convention when dealing with arithmetic operations on character variables and not C’s. For example, in PHP and Perl $a = ‘Z’; $a++; turns $a into ‘AA’, while in C a = ‘Z’; a++; turns a into ‘[‘ (ASCII value of ‘Z’ is 90, ASCII value of ‘[‘ is 91). Note that character variables can be incremented but not decremented and even so only plain ASCII characters (a-z and A-Z) are supported. Incrementing/decrementing other character variables has no effect, the original string is unchanged.

当处理字符变量而非C的算术运算时,PHP遵循Perl的约定。 例如,在PHP和Perl中,$ a ='Z'; $ a ++; 将$ a转换为“ AA”,而在C中将a转换为“ Z”; a ++; 将a变成“ [”(“ Z”的ASCII值为90,“ [”的ASCII值为91)。 请注意,字符变量可以递增但不能递减,即使如此,仅支持纯ASCII字符(az和AZ)。 递增/递减其他字符变量无效,原始字符串不变。

价值出现的奥秘 (The Mystery of Value Appearance)

You’re a real array master in PHP, admit it. Don’t be shy. You already know everything about how to create, manage, and delete arrays. Nonetheless, the next example might surprise you at first sight.

承认您是PHP的真正数组大师。 别害羞 您已经了解有关如何创建,管理和删除阵列的所有知识。 但是,下一个示例可能会让您一见钟情。

Often you work with arrays and need to search if a given value is in an array. PHP has a function for this, in_array(). Let’s see it in action:

通常,您使用数组,并且需要搜索给定值是否在数组中。 PHP为此提供了一个函数in_array() 。 让我们来看看它的作用:

<?php
$array = array(
  'isReady' => false,
  'isPHP' => true,
  'isStrange' => true
);
var_dump(in_array('sitepoint.com', $array));

What will be the output? Place your bets and let’s check it.

输出是什么? 下注,让我们检查一下。

true

Isn’t this a little bit strange? We have an associative array where its values are all boolean and if we search for a string, we got true. Has this value magically appeared? Let’s see another example.

这有点奇怪吗? 我们有一个关联数组,其值均为布尔值,如果我们搜索字符串,则为true 。 这个价值神奇地出现了吗? 让我们来看另一个例子。

<?php
$array = array(
  'count' => 1,
  'references' => 0,
  'ghosts' => 1
);
var_dump(in_array('aurelio', $array));

And what we get is…

而我们得到的是……

true

Once again the in_array() function returns true. How is this possible?

in_array()函数再次返回true。 这怎么可能?

You’re experiencing one of both best and worst, loved and hated PHP features. PHP isn’t strongly typed and this is where the error starts. In fact, all the following values, if compared in PHP, are considered the same unless you use the identity operator:

您正在体验最好的和最差的,喜爱的和讨厌PHP功能之一。 PHP不是强类型的,这是错误开始的地方。 实际上,以下所有值(如果在PHP中进行比较)都将视为相同,除非您使用身份运算符:

  • 0

    0
  • false

  • “”

    “”
  • “0”

    “ 0”
  • NULL

    空值
  • array()

    array()

By default, the in_array() function uses the loose comparison, a non-empty ("") and non-zero-filled ("0") string is equal to true and to all non-zero numbers (like 1). Hence, in the first example we got true because 'sitepoint.com' == true, while in the second we have 'aurelio' == 0.

默认情况下, in_array()函数使用松散比较,非空( "" )和非零填充( "0" )字符串等于true并且等于所有非零数字(例如1 )。 因此,在第一个示例中,因为'sitepoint.com' == true ,所以'sitepoint.com' == true ,而在第二个示例中,我们的'aurelio' == 0

To solve the problem you’ve to use the third and optional parameter of in_array() that allows you to compare the values strictly. So, if we write:

要解决该问题,您必须使用in_array()的第三个和可选参数,该参数允许您严格比较这些值。 所以,如果我们写:

<?php
$array = array(
  'count' => 1,
  'references' => 0,
  'ghosts' => 1
);
var_dump(in_array('aurelio', $array, true));

we’ll finally get false as we expect!

我们最终会像我们期望的那样false

结论 (Conclusions)

Throughout this article you’ve seen some strange and unexpected behaviors you might experience while using PHP. The lessons to take away from these examples are:

在本文中,您已经看到使用PHP时可能会遇到的一些奇怪的意外行为。 这些示例的经验教训是:

  • Never trust floating point numbers

    永远不要相信浮点数
  • Double check what data type you’ve before using them in operations

    在操作中使用它们之前,请仔细检查您拥有哪种数据类型
  • Be aware of the problems of loose comparisons and loose data types

    注意松散比较和松散数据类型的问题

If you’re an advanced user, you probably already knew them already, but a refresher is never worthless.

如果您是高级用户,则可能已经知道它们,但是复习从来都不是毫无价值的。

Image via Fotolia

图片来自Fotolia

翻译自: https://www.sitepoint.com/3-strange-php-facts-you-may-not-know/

奇怪的php

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值