【问题标题】:What factors make PHP Unicode-incompatible?什么因素使 PHP Unicode 不兼容?
【发布时间】: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>

【问题讨论】:

    标签: php unicode


    【解决方案1】:

    几年前 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 中”,这意味着在处理字符串时必须非常小心和明确确保在输入、存储(数据库)和输出过程中始终将字符串保持在正确的编码中,这很容易出错。

    【讨论】:

    • 这不是我要问的。哪些因素导致 PHP Unicode 不兼容?
    • 不想在这里打死马,但是“PHP 6 将有_____”多年来一直是常见的副词。该死的东西什么时候出?既然旧的 php 代码如此普遍,它还会被广泛采用吗?
    • PHP 5 也有同样的问题,因为这个原因,有些人仍在运行 php 4(实际上我自己的 WebHost 默认使用 PHP 4,我必须使用 .htaccess 来获取 PHP 5,他们甚至仍然提供 PHP 3(!))。当 PHP 6 最终问世时,肯定需要很长时间才能大规模采用。
    • 我喜欢您链接到 Joel 的一篇文章,该文章指出 PHP 落后且尚未正确支持 Unicode - 他写于 2003 年!
    【解决方案2】:

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

    至于技术问题——在一个建立在“一个字符等于一个字节”的假设之上的生态系统中实现 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 的宏伟大厦,将他们的胶带扔到每一个用另一个钉子无法解决的问题上。当然,那栋建筑会受到每一次吹来的风的影响,例如偶尔合法但出乎意料的角色。

    看到这个特定的线程活跃了八年并不能完全灌输信心,从现在起八年后情况会好转。

    【讨论】:

    • 您的回答可能看起来有偏见,但您肯定提出了一些观点。来自 PHP 开发人员的 +1。
    【解决方案3】:

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

    1. 它泄露了一个实现细节:您应该能够在不知道实现者如何选择表示数据的情况下使用字符的抽象 - 可能取决于适合他们将所有内容表示为 UTF16 或 UTF32 的平台,其中万一一切都是多字节的,字符抽象的用户不应该关心。
    2. 这是一个杂项:除了我们都“真正知道”字符串是字节序列的过时思维习惯之外,我们现在必须知道有时字节会聚集成称为 Unicode 字符的东西,并且各地都有特殊情况来处理。
    3. 就像老鼠想吃大象一样。通过将 Unicode 构建为 ASCII 的扩展(我们有普通的字符串,我们有 mb_strings),它会让事情变得错误,并且在处理需要超过一个字节的有趣曲线的字符时需要什么特殊情况。如果您将 Unicode 视为为您需要的任何字符提供抽象空间,那么 ASCII 将被容纳在其中,无需将其视为特殊情况。

    【讨论】:

      【解决方案4】:

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

      另外,一些extremely popular encodings 仍然受到 PHP 的明确支持,大概是因为这样做并保持向下兼容是不可能的。

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          许多字符串函数只是 C 库等价物的薄包装,它也将所有内容视为字节序列。另一个原因是 PHP 携带了许多不必要的向后兼容包袱,因此陷入了来自 3&4 的错误设计决策。

          也许有了 5.3 的命名空间,他们最终将有办法逐步淘汰旧功能。

          【讨论】:

            【解决方案7】:

            “支持”的意思是“原生支持”。查看this 获取详细信息。

            【讨论】:

            • 那篇文章已经有将近 4 年的历史了——现在几乎没有准确的信息。
            • 后未来主义者,那篇文章到现在已经快六年了,似乎几乎没有什么变化。
            猜你喜欢
            • 1970-01-01
            • 2018-07-06
            • 1970-01-01
            • 2012-05-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-03
            相关资源
            最近更新 更多