哪些因素使PHP Unicode不兼容?

时间:2009-02-20 23:48:56

标签: php unicode

我可以在我的脚本中使用UTF-8字符。

事实上可以have names of variables and functions contain Unicode characters

还有mb_string extension处理多字节字符串,但在无数篇文章中,PHP因其缺乏Unicode支持而受到批评。

我不明白;为什么PHP说不支持Unicode?

7 个答案:

答案 0 :(得分:43)

几年前启动PHP时,UTF-8并不受支持。我们谈论的是像Windows 98 / Me这样的非Unicode操作系统仍处于当前状态,而其他大型语言(如Delphi)也是非Unicode的时候。从第1天开始,并非所有语言都设计为使用Unicode,并且在不破坏大量内容的情况下将语言完全更改为Unicode非常困难。例如,Delphi仅在一两年前就变成了Unicode兼容,而其他语言如Java或C#则是从第1天开始用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,这意味着:不再有代码页,理论上你不会搞砸。我推荐关于Unicode和字符集的Joel's article,但基本上归结为:如何在内部存储字符串,而PHP的答案是“不在Unicode中”,这意味着你必须非常小心和明确处理字符串以确保在输入,存储(数据库)和输出期间始终将字符串保持在正确的编码中,这是非常错误的。

答案 1 :(得分:35)

我认为这主要是文化上的困难,而不是技术上的困难。

关于技术问题 - 并且在基于“一个字符等于一个字节”的假设的生态系统中实现unicode并不是一件容易的事情 - 开发人员可能已经复制了大部分java或python的努力(自2001年左右以来,后者具有良好且大部分工作的unicode兼容性),但他们从未这样做过。

当我阅读the discussion thread attached to the official, current documentation for php's utf8_encode() function时,我感到眩晕。

firstoff,该函数称为utf8_encode();但是,文档声明它预期的字符串应该在ISO-8859-1(a.k.a. latin-1)中。这是sooo php,那是80年代的sooo。

大多数评论者似乎认为unicode是一种负担。有很多建议如何转换未知内容的字符串,如何处理混合编码的字符串(wtf?),或处理通常导致破坏的代码点,因为它们超出了该函数的四个字节代码点限制。

讨论以修正为中心,以消除波形或避免该函数行为的问题部分。而且,对我来说,是sooo php:每个人都在做修复,很少有东西是以一种基本正确的方式实现的。如果你认为这是我的诽谤,这里有一些花絮:

  

虽然如果该文件已经是UTF-8,这似乎打破了德国的Umlaute [äöü]。

(未能理解utf-8在两次应用时不适用)

  

看看iconv()函数,它提供了一种从8859和可怕的1252转换为UTF8的方法

(好点:对部分php开发人员的现有技术的忽视;相反,错误自己的实现)

  

使用preg_match检测是否需要utf8_encode [...],不包括代名词[...],不包括overlongs

(建议从字符串中静默删除所有有问题的内容,只留下那些不会破坏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 bug

(一个很大程度上只存在因为unicode没有正确实现的问题的修复。我们还了解到,utf8_encode()函数不仅会放弃每个代码点超过4个字节,而且如果结果也会中断(或输出?)文本超过5000个字符的限制)

我可以继续这样下去。你已经明白了这一点:从这个线程判断,php社区听起来并不像他们在任何地方都准备好了解编码和字符集的全部内容,一般来说构建一个完善的基础设施需要什么,或者特别是以适当的方式实现unicode。相反,他们正在使用他们的脚手架,他们的纸板,他们的钉子和锤子,继续建造这个名为php的宏伟大厦,将他们的胶带扔在每一个用另一个钉子无法解开的问题上。当然,这座建筑将遭受每一次吹来的风,例如偶尔合法但意外的性格。

看到这个特殊的线程活跃了八年并没有完全灌输信心,从现在起八年内情况会好转。

答案 2 :(得分:11)

“多字节字符”的概念是问题的核心。

  1. 它漏掉了一个实现细节:你应该能够在不知道实现者如何选择代表数据的情况下使用角色的抽象 - 可能取决于它适合它们的平台,将所有东西表示为UTF16或UTF32,其中case一切都是多字节的,而不是字符抽象的用户应该关心。
  2. 这是一个kludge:除了一个过时的思维习惯,我们都“真的知道”字符串是字节序列,我们现在必须知道有时字节聚集成称为Unicode字符的东西,并且到处都有特殊情况来处理它。
  3. 就像一只试图吃大象的老鼠。通过将Unicode构建为ASCII的扩展(我们有普通字符串并且我们有mb_strings),它会以错误的方式解决问题,并且需要处理需要多个字节的有趣曲线所需的特殊情况。如果您将Unicode视为为您需要的任何字符提供抽象空间,则可以使用ASCII,而无需将其视为特殊情况。

答案 3 :(得分:5)

您自己说:为了正确处理包含多字节字符的字符串,您需要使用扩展名。忘记在任何地方使用扩展功能而不是更熟悉的“普通”功能,并且您的数据被肢解。如果您使用尚未更新的第三方库在任何地方使用扩展功能,也会发生同样的情况。

此外,PHP仍支持extremely popular encodings许多 ,大概是因为不可能这样做并保持向下兼容。

答案 4 :(得分:3)

许多常见的扩展都没有unicode支持,或者(更糟糕的是)你“需要知道”字符串包含unicode / utf-8序列,例如XMLReader。 PHP的glob()在win32上调用FindFirstFileA或FindFirstFileW可能会产生很大的不同。
另一个(小得多但令人惊讶的往往是烦恼的来源)问题是PHP无法识别的BOM。

答案 5 :(得分:3)

许多字符串函数只是围绕C库等价物的瘦包装器,它们也将所有内容视为字节序列。另一个原因是PHP带来了许多不必要的向后兼容行李,因而陷入了3& 4的糟糕设计决策。

也许使用5.3的命名空间,他们终于可以逐步淘汰旧功能了。

答案 6 :(得分:2)

“支持”的含义是“原生支持”。请查看this以获取详细信息。