什么因素使PHP Unicode不兼容?

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

实际上,可以使用变量名称,而函数包含Unicode字符。

还有mb_string扩展名,用于处理多字节字符串,但是在无数文章中,PHP因缺乏Unicode支持而受到批评。

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

moo asked 2020-08-11T16:45:29Z
7个解决方案
45 votes

几年前启动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关于Unicode和字符集的文章,但从本质上讲,它可以归结为:字符串是如何在内部存储的,而PHP的答案是“ Not in Unicode”,这意味着在处理字符串时必须非常小心和明确。 确保在输入,存储(数据库)和输出期间始终将字符串保持正确的编码,这很容易出错。

Michael Stum answered 2020-08-11T16:45:48Z
36 votes

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

至于技术问题-以及在基于“一个字符等于一个字节”的假设基础上在生态系统中实现unicode并非一件容易的事-开发人员可能已经复制了Java或python的许多努力(后者 自2001年左右以来具有良好的体面且在很大程度上可以兼容unicode),但他们从未做到过。

当我阅读附带在php utf8_encode()88的官方最新文档中的讨论线程时,我感到眩晕。

首先,该函数称为utf8_encode(); 但是,文档指出期望的字符串应位于ISO-8859-1(又称latin-1)中。 那是php,那是80年代。

大多数评论者似乎将unicode视为负担。 有很多建议如何转换“未知内容”的字符串,如何处理“混合编码的字符串”(wtf?),或处理通常会导致中断的代码点,因为它们超出了该函数每字节四字节的范围。 代码点限制。

讨论集中在修正上,以消除花样或避免该函数行为的有问题的部分。 对我来说,那真是太糟糕了:每个人都在做补丁,很少有事情以根本正确的方式实现。 如果您认为这对我不利,请参考以下提示:

尽管如果该文档已经是UTF-8,这似乎使德语Umlaute [äöü]破了。

(无法理解utf-8不适用于两次)

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

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

使用preg_match来检测是否需要utf8_encode [...],而不是代理,[...]

(建议静默擦除字符串中所有有问题的内容,只保留那些不会破坏的内容utf8_encode();这可能使文本不可读(或完全消失),但是,没有更多错误消息了)

仅在还没有UTF-8的情况下才对字符串进行编码[...] utf8_encode()

(正如另一位评论者所指出的那样,这行不通:

$str = 'áéóú'; // ISO-8859-1
mb_detect_encoding($str, 'UTF-8'); // 'UTF-8'
mb_detect_encoding($str, 'UTF-8', true); // false

所以在这里,我们正在研究一个被另一个bug替代的bug。 狩猎愉快。 同样,他们似乎在这里提出的建议是使用启发式(慢速,不确定)方法解决问题,而启发式方法可以并且应该通过机械(快速,确定)方法解决)

utf8_ [encode | decode]实际上也将翻译Windows-1252字符,而不仅仅是文档说明中的ISO-8859-1

(您永远都不能依靠官方的php文档来获得清晰或详尽的信息-您必须始终阅读多年的用户经验,没有人会反馈给文档)

我一直在研究is_utf8函数,并希望将其发布在这里,除其他功能外,我还考虑了5000个char bug

(此问题的解决方案仅在很大程度上由于未正确实施unicode而存在。我们还了解到3006924465977687689088函数不仅会放弃每个代码点超过4个字节,而且如果结果(或输出?)文本超过 最多5000个字符)

我可以这样下去。 您已经有了主意:从这个线程来看,php社区听起来似乎并没有准备好掌握所有编码和字符集的含义,一般而言,或者建立一个健全的基础架构所需的一切, 以适当的方式实现unicode。 相反,他们正在使用脚手架,纸板,钉子和锤子,然后继续建造这个名为php的宏伟的大厦,将胶带贴在用钉子无法解决的所有问题上。 当然,建筑物会受到每一个吹来的风的影响,例如偶尔出现的合法但出乎意料的特征。

看到这个特定的线程已经运行了八年并不能完全灌输信心,从现在起的八年里情况会变得更好。

flow answered 2020-08-11T16:47:43Z
11 votes

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

  1. 它泄漏了一个实现细节:您应该能够使用字符的抽象,而无需知道实现者如何选择代表数据-可能取决于它适合他们将平台表示为UTF16或UTF32的平台,在这种情况下,一切 多字节,而不是字符抽象的用户应该关心的。
  2. 这太过分了:在过时的习惯上,我们都“真正地知道”字符串是字节序列,现在我们必须知道,有时字节会聚集成在一起,称为Unicode字符,并且具有特殊含义。 各地都有案件处理。
  3. 就像老鼠想吃大象一样。 通过将Unicode构造为ASCII的扩展(我们有普通的字符串,我们有mb_strings),它以错误的方式解决了问题,并且挂断了处理特殊花体字符需要多个字节的特殊情况。 如果您将Unicode视为为所需的任何字符提供抽象空间,则ASCII会被容纳在其中,而无需将其视为特殊情况。
answered 2020-08-11T16:48:19Z
5 votes

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

另外,PHP仍然明确不支持许多非常流行的编码,这可能是因为这样做是不可能的,并且保持向下兼容。

Michael Borgwardt answered 2020-08-11T16:48:45Z
3 votes

许多常见的扩展名不支持unicode,或者(甚至更糟)您“需要知道”字符串包含unicode / utf-8序列,例如XMLReader。 而且,如果PHP的glob()在win32上调用FindFirstFileA或FindFirstFileW,则可能会有很大的不同。
另一个(小得多,但令人惊讶的经常是烦人的原因)问题是PHP无法识别的BOM。

VolkerK answered 2020-08-11T16:49:34Z
3 votes

许多字符串函数只是C库等效项的薄包装,它们还将所有内容视为字节序列。 另一个原因是PHP携带了许多不必要的向后兼容包,因此陷入3&4的糟糕设计决策中。

也许使用5.3的命名空间,他们最终将有一种逐步淘汰旧功能的方式。

answered 2020-08-11T16:49:59Z
2 votes

“支持”是指“本地支持”。 查看此以获得详细信息。

muratgu answered 2020-08-11T16:50:20Z
translate from https://stackoverflow.com:/questions/571694/what-factors-make-php-unicode-incompatible