什么因素使得PHP的Unicode不兼容?
我能够在脚本中使用UTF-8字符。
事实上,可以使variables和函数的名称包含Unicode字符 。
还有处理多字节string的mb_string扩展 ,但是在无数文章中,PHP被批评为缺乏Unicode支持。
我不明白 为什么PHP说不支持Unicode?
几年前PHP开始的时候,UTF-8并没有得到真正的支持。 我们谈论的是像Windows 98 / Me这样的非Unicode操作系统仍然是最新的,而像Delphi这样的其他大型语言也是非Unicode的。 并非所有的语言都是从第1天开始用Unicode来devise的,并且在不破坏大量内容的情况下完全改变您的语言为Unicode是很困难的。 例如,Delphi只在一两年前变成了Unicode兼容,而其他语言如Java或C#则是从第一天开始用Unicode编码的。
所以当PHP发展成为PHP 3,PHP 4和现在的PHP 5时,根本没有人决定添加Unicode。 为什么? 大概是保持兼容现有的脚本或因为utf8_de /编码和mb_string已经存在和工作。 我不确定,但我坚信这与有机增长有关。 function不是简单地存在默认情况下,他们必须由某人写,而这根本不会发生在PHP呢。
编辑:好吧,我读错了问题。 问题是:string是如何在内部存储的? 如果我input“Währung”或“Écriture”,哪个编码用于创build使用的字节? 在PHP的情况下,它是ASCII代码页。 这意味着:如果我使用ISO-8859-15对string进行编码,并使用中文代码页对其进行解码,则会得到奇怪的结果。 另一种select是用像C#或Java这样的语言,其中一切都以Unicode存储,这意味着:没有代码页了,理论上你不能搞砸了。 我推荐Joel关于Unicode和字符集的文章 ,但实际上它归结为:string是如何在内部存储的,PHP的答案是“不是Unicode”,这意味着在处理string时必须非常小心和明确确保在input,存储(数据库)和输出期间始终保持string正确的编码,这是非常错误的。
我相信这在很大程度上是文化上的困难,而不是技术上的。
至于技术上的问题—在一个基于“一个字符等于一个字节”假设的生态系统中实现unicode的开发者可能已经复制了很多java或python的工作(后者自2001年左右以来,体面的和大部分的unicode兼容性),但他们从来没有。
当我读到官方的讨论post,php的utf8_encode()
函数的最新文档 ,我感到眩晕。
首先,该函数被称为utf8_encode()
; 然而,文档指出,它期望的string预计在ISO-8859-1(aka latin-1)中。 这是sooo PHP,这是80多岁。
大多数评论者似乎认为unicode是一种负担。 有许多提议如何转换未知内容的string,如何处理混合编码的string,或者处理通常会导致破坏的代码点,因为它们超出了函数的每字节4字节,码点限制。
讨论是围绕fixups摆脱摆动或避免该function的行为有问题的部分。 对我来说,这是很好的PHP:每个人都只是在做修复,几乎没有什么东西是以基本正确的方式实现的。 如果你认为这是对我的诽谤,这里有一些小技巧:
虽然这似乎打破德国Umlaute [äöü]如果文件已经是UTF-8。
(不明白utf-8的devise不适用于两次)
看看iconv()函数,它提供了一种从8859和可怕的1252转换为UTF8的方法
(好点:部分PHP开发人员忽略了现有技术;相反,越野车本身的实现)
使用preg_match来检测是否需要utf8_encode […]除了overlongs
(build议静静地从string中清除所有有问题的内容,只留下那些不会破坏utf8_encode()
;这可能会使文本不可读(或完全消失),但是,不会有更多的错误消息)
只有当它还不是UTF-8
mb_detect_encoding($s, "UTF-8")
(正如另一位评论者所指出的,这是行不通的:
$str = 'áéóú'; // ISO-8859-1 mb_detect_encoding($str, 'UTF-8'); // 'UTF-8' mb_detect_encoding($str, 'UTF-8', true); // false
所以在这里我们正在看一个错误被另一个replace。 快乐狩猎。 另外,他们似乎在这里提出的是使用启发式(缓慢的,不确定的)手段来解决问题,这意味着可以并且应该用机械(快速,确定的)手段来解决)
utf8_ [encode | decode]实际上也会翻译windows-1252字符,而不仅仅是从/到ISO-8859-1
(你永远不能依靠官方的PHP文档来清楚或详尽的 – 你必须经常阅读多年的用户体验,没有人会反馈到文档)
我一直在做一个is_utf8函数,想把它发布在这里,除此之外,我还考虑到了5000个字符的bug
(这个问题的解决方法很大程度上只是因为unicode没有正确实现而存在,我们也知道utf8_encode()
函数不仅会放弃每个代码点超过4个字节,而且如果结果(或输出?)文本超过5000个字符的限制)
我可以像这样继续下去。 你已经有了这个想法:从这个线程来看,php社区听起来并不像他们随时准备好掌握什么编码和字符集都是关于什么,它需要build立一个完善的基础设施,特别是以适当的方式实施unicode。 相反,他们正在使用他们的脚手架,他们的纸板,他们的钉子和锤子,并继续build设这个伟大的大厦称为PHP,扔在他们的胶带在每一个不能用另一个钉子撤消的问题。 当然,这座build筑会受到每一个吹来的风的影响,比如偶尔的合法但是意想不到的特性。
看到这个特殊的线索活跃了八年,并没有给人以充足的信心,从现在开始的八年里情况将会好转。
“多字节字符”的概念是问题的核心。
- 它泄漏了一个实现的细节:你应该能够在不知道实现者如何select表示数据的情况下使用angular色的抽象 – 可能取决于它适合他们的平台,以UTF16或UTF32表示一切,在这种情况下,一切都是多字节,而不是字符抽象的用户应该关心。
- 这是一个混乱:除了我们所有人都“真正知道”string是字节序列的思维习惯之外,我们现在必须知道有时候这些字节会聚集成一个叫做Unicode字符的东西,并且有特殊的案件到处都是要处理的。
- 这就像一只试图吃大象的老鼠。 通过将Unicode作为ASCII的扩展(我们有正常的string,我们有mb_strings),把事情弄错了,并挂上了什么特殊的情况下需要处理与需要多于一个字节的有趣的歪曲字符。 如果您将Unicode视为为您需要的任何字符提供抽象空间,那么ASCII将被容纳在其中,而不需要将其视为特殊情况。
您自己说:为了正确处理包含多字节字符的string,您需要使用扩展名。 忘记任何地方使用扩展function,而不是更熟悉的“正常”的,而你的数据是残缺的。 如果您使用尚未更新的第三方库来使用扩展function,则会发生同样的情况。
此外,许多非常stream行的编码仍然明确地不被PHP支持,大概是因为这是不可能的,并保持向下兼容。
许多常见的扩展没有unicode支持,或者(甚至更糟糕),你需要知道一个string包含unicode / utf-8序列,比如XMLReader。 它可以使相当不同的PHP的glob()在win32上调用FindFirstFileA或FindFirstFileW。
另一个(小得多,但令人惊讶的往往是烦人的来源)问题是PHP无法识别的BOM。
许多string函数只是C库的等价物周围的薄包装,它也把所有的东西当作一个字节序列。 另一个原因是,PHP带着许多不必要的向后兼容的行李,因而被3&4的糟糕的devise决定所困。
也许在5.3的命名空间里,他们终于有了一种逐步淘汰旧function的方法。
“支持”是指“本地支持”。 看看这个来获取详细信息。