PHP如何在内部表示字符串?


18

UTF8?
UTF16?

PHP中的字符串是否也跟踪使用的编码?

让我们以这个脚本为例。说我跑步:

$original = "शक्नोम्यत्तुम्";

实际发生了什么?

显然,我认为$original不会只包含7个字符。这些字形必须在此处分别由几个字节表示。

然后我做:

$converted = mb_convert_encoding ($original , "UTF-8");

会发生什么$converted?有$converted什么不同$original

它会与字节序列完全相同,$original但编码不同吗?


1
哪个版本的PHP?PHP <6无法处理本机UTF-8。尽管有一些软件包和方法可以帮助/解决此问题。Google与utf-8和php一起娱乐。然后切换到另一个平台而不是PHP。:)
Andrew T Finnell 2012年

4
PHP <6?这将包括有史以来发布的所有版本的PHP ...
tdammers 2012年

1
另外,PHP 可以处理UTF-8,它没有专用的数据类型,因此您必须注意自己在做什么。
tdammers 2012年

Answers:


22

一个PHP字符串只是一个字节序列,没有任何编码标记。字符串值可以来自各种来源:客户端(通过HTTP),数据库,文件或源代码中的字符串文字。PHP将所有这些读取为字节序列,并且从不提取任何编码信息。

只要所有数据源和目标都使用相同的编码,最糟糕的事情可能是字符串位置错误(如果使用多字节编码),因为PHP会计算字节而不是字符。

但是,如果编码不匹配(例如,您在存储为UTF-8的源文件中写入字符串文字,然后将其发送到需要Latin-1的数据库中),PHP将不会为您执行任何转换:愉快地复制原始字节。

最好的解决方案是这样的:

  • 将PHP的内部编码设置为UTF-8。
  • 将所有源文件另存为UTF-8。
  • 使用UTF-8作为输出编码(不要忘记发送适当的Content-type标头)。
  • 将数据库连接设置为使用UTF-8(SET NAMES UTF8在MySQL中)。
  • 尽可能将其他所有配置为UTF-8。
  • 对于您无法控制的任何内容(例如,第三方Web服务),请确保您知道该编码,并尽早转换为UTF-8,并尽可能晚地转换回另一种编码。

为什么选择UTF-8?因为它可以表示所有Unicode字符,从而取代了所有现有的7位和8位编码,并且因为它与ASCII二进制兼容,所以每个有效的ASCII字符串也是一个有效的UTF-8字符串(但不是vv )。

在您的示例中,将发生这种情况。

首先,保存您的源文件;您的文本编辑器可能配置为使用UTF-8,因此您的字符串文字最终以UTF-8编码在磁盘上。PHP读取该文件,并将字符串解释为一系列字节;$original现在包含一个由7个字符组成的UTF-8编码字符串,这只是一个字节序列(尽管它包含7个以上的字节,因为每个字符由两个或多个字节表示)。如果您随后调用echo $original,则编码后的字符串将按原样发送给客户端;如果您告诉客户期望使用UTF-8,那么一切都很好,但是如果没有,PHP将无法告诉您区别,最终您将在浏览器中产生垃圾。作为实验,请尝试以下操作:

$original = "शक्नोम्यत्तुम्";
echo strlen($original);

strlen 是与编码无关的,并且假定使用固定宽度的8位编码,即每个字符一个字节,因此它将计算字节,而不是字符。


因此,$ converted将表示相同的字符串,但使用其他编码。PhP存储的实际原始编码将有所不同。
user4951 2012年

2
PHP店字节,而不是字符,它不知道在所有编码(尽管有些库函数做的:我会重复它。
tdammers

1
哦,是“ PHP”,而不是“ PhP”。
tdammers 2012年

2
如果原始字节相同,则$ original和$ converted之间有什么区别。这就是我要问的。
user4951 2012年

2
哦,那是你的意思。是的,原始字节根据编码转换而变化。PHP不会记住编码,因此,如果将字符串从utf-8转换为latin-1,然后将结果视为utf-8,则会看到奇怪的结果。
tdammers 2012年
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.