【发布时间】:2010-10-08 23:20:47
【问题描述】:
我可以在我的脚本中使用 UTF-8 字符。
事实上have names of variables and functions contain Unicode characters是可以的。
还有处理多字节字符串的mb_string extension,但在无数文章中,PHP 因缺乏 Unicode 支持而受到批评。
我不明白;为什么说 PHP 不支持 Unicode?p>
【问题讨论】:
我可以在我的脚本中使用 UTF-8 字符。
事实上have names of variables and functions contain Unicode characters是可以的。
还有处理多字节字符串的mb_string extension,但在无数文章中,PHP 因缺乏 Unicode 支持而受到批评。
我不明白;为什么说 PHP 不支持 Unicode?p>
【问题讨论】:
几年前 PHP 刚开始的时候,还没有真正支持 UTF-8。我们谈论的是一个像 Windows 98/Me 这样的非 Unicode 操作系统仍然流行的时代,而像 Delphi 这样的其他大型语言也是非 Unicode 的时候。从第一天起,并非所有语言的设计都考虑到了 Unicode,并且在不破坏很多东西的情况下将您的语言完全更改为 Unicode 是很困难的。例如,Delphi 在一两年前才开始兼容 Unicode,而其他语言(如 Java 或 C#)从第一天开始就采用 Unicode 设计。
所以当 PHP 成长为 PHP 3、PHP 4 和现在的 PHP 5 时,根本没有人决定添加 Unicode。为什么?大概是为了与现有脚本保持兼容,或者因为 utf8_de/encode 和 mb_string 已经存在并且可以工作。我不确定,但我坚信这与有机增长有关。功能并不是默认就存在的,它们必须由某人编写,而这在 PHP 中还没有发生。
编辑:好的,我读错了问题。问题是:字符串如何在内部存储?如果我输入“Währung”或“Écriture”,哪个编码用于创建使用的字节?对于 PHP,它是带有代码页的 ASCII。这意味着:如果我使用 ISO-8859-15 对字符串进行编码,然后使用一些中文代码页对其进行解码,则会得到奇怪的结果。另一种选择是在 C# 或 Java 等语言中,所有内容都存储为 Unicode,这意味着:不再有代码页,理论上你不能搞砸。我推荐 Joel's article 关于 Unicode 和字符集,但本质上归结为:字符串如何在内部存储,PHP 的答案是“不在 Unicode 中”,这意味着在处理字符串时必须非常小心和明确确保在输入、存储(数据库)和输出过程中始终将字符串保持在正确的编码中,这很容易出错。
【讨论】:
我认为这主要是文化上的困难,而不是技术上的困难。
至于技术问题——在一个建立在“一个字符等于一个字节”的假设之上的生态系统中实现 unicode 并不是一件简单的事情——开发人员可能已经复制了 java 或 python 的大部分工作(后者自 2001 年左右以来就具有良好且大部分工作的 unicode 兼容性),但他们从未这样做过。
当我阅读the discussion thread attached to the official, current documentation for php's utf8_encode() function 时,我有一种眩晕的感觉。
首先,该函数称为utf8_encode();但是,文档指出它期望的字符串应该是 ISO-8859-1(又名 latin-1)。那是sooo php,那是80年代。
大多数评论者似乎认为 unicode 是一种负担。有很多建议如何转换“未知内容”的字符串,如何处理“混合编码的字符串”(wtf?),或者处理通常会导致损坏的代码点,因为它们超出了该函数的每四个字节代码点限制。
讨论集中在修正以消除曲线或避免该函数行为的问题部分。对我来说,这就是 php:每个人都只是在做修复,很少有事情以基本正确的方式实现。如果你认为这是对我的诽谤,这里有一些花絮:
尽管如果文档已经是 UTF-8,这似乎会破坏德语变音符号 [äöü]。
(未能理解 utf-8 在应用两次时无法正常工作)
查看 iconv() 函数,它提供了一种将 8859 和可怕的 1252 转换为 UTF8 的方法
(好点:部分 php 开发人员忽略了现有技术;取而代之的是错误的自己的实现)
使用 preg_match 检测是否需要 utf8_encode [...] 排除代理 [...] 排除超长
(建议默默地从字符串中删除所有有问题的内容,只留下那些不会破坏 utf8_encode() 的内容;这可能会使文本不可读(或完全消失),但是,嘿,不再有错误消息)
仅当字符串还不是 UTF-8 [...]
mb_detect_encoding($s, "UTF-8")时才对字符串进行编码
(正如 by another commenter 指出的那样,这是行不通的:
$str = 'áéóú'; // ISO-8859-1
mb_detect_encoding($str, 'UTF-8'); // 'UTF-8'
mb_detect_encoding($str, 'UTF-8', true); // false
所以在这里我们正在研究一个错误被另一个错误所取代。快乐的狩猎。此外,他们似乎在这里提出的是使用启发式(缓慢,不确定)手段解决问题,可以而且应该使用机械(快速,确定)手段来解决)
utf8_[encode|decode] 实际上也会翻译 windows-1252 字符,而不仅仅是文档中所说的从/到 ISO-8859-1
(你永远不能依赖官方的 php 文档来清晰或详尽——你必须始终阅读多年的用户经验,没有人会反馈给文档)
我一直在研究一个 is_utf8 函数并想在这里发布它,除此之外我还考虑了 5000 char 错误
(解决了一个主要因为 unicode 未正确实现而存在的问题。我们还了解到,utf8_encode() 函数不仅会放弃每个代码点超过 4 个字节,而且如果结果(或输出)也会中断?) 文本超过 5000 个字符的限制)
我可以这样继续下去。你已经明白了:从这个线程来看,php 社区听起来根本不像他们准备好掌握编码和字符集的全部内容,一般来说构建健全的基础设施需要什么,或者具体来说,以适当的方式实现 unicode。相反,他们使用他们的脚手架、他们的纸板、他们的钉子和锤子,继续建造这座名为 php 的宏伟大厦,将他们的胶带扔到每一个用另一个钉子无法解决的问题上。当然,那栋建筑会受到每一次吹来的风的影响,例如偶尔合法但出乎意料的角色。
看到这个特定的线程活跃了八年并不能完全灌输信心,从现在起八年后情况会好转。
【讨论】:
“多字节字符”的概念是问题的核心。
【讨论】:
您自己说:为了正确处理包含多字节字符的字符串,您需要使用扩展名。忘记在任何地方使用扩展功能而不是更熟悉的“正常”功能,您的数据就会被破坏。如果您使用尚未更新的第三方库以在任何地方使用扩展功能,也会发生同样的情况。
另外,一些extremely popular encodings 仍然不受到 PHP 的明确支持,大概是因为这样做并保持向下兼容是不可能的。
【讨论】:
许多常见的扩展不支持 unicode,或者(更糟糕的是)您“需要知道”字符串包含 unicode/utf-8 序列,例如 XMLReader。 PHP 的 glob() 在 win32 上调用 FindFirstFileA 或 FindFirstFileW 会产生很大的不同。
另一个(小得多但令人惊讶的经常是烦恼的根源)问题是 PHP 无法识别的 BOM。
【讨论】:
许多字符串函数只是 C 库等价物的薄包装,它也将所有内容视为字节序列。另一个原因是 PHP 携带了许多不必要的向后兼容包袱,因此陷入了来自 3&4 的错误设计决策。
也许有了 5.3 的命名空间,他们最终将有办法逐步淘汰旧功能。
【讨论】:
“支持”的意思是“原生支持”。查看this 获取详细信息。
【讨论】: