代码之家  ›  专栏  ›  技术社区  ›  Gordon Haim Evgi

方法、常量、变量和字段的外来名称——bug还是feature?

  •  33
  • Gordon Haim Evgi  · 技术社区  · 14 年前

    在一些混乱的评论之后

    我想我提出了一个问题。根据PHP手册,有效的类名应该与 [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]* . 但显然,这不是强制执行的,也不适用于其他任何情况:

    define('π', pi());
    var_dump(π);
    
    class ␀ {
        private $␀ = TRUE;
        public function ␀()
        {
            return $this->␀;
        }
    }
    
    $␀ = new ␀;
    var_dump($␀ );
    var_dump($␀->␀());
    

    工作正常(即使我的IDE不能显示__)。有什么博学的人能帮我把这事说清楚吗?我们能用Unicode码吗?如果是,从什么时候开始?不是说我真的会 希望 除了 A-Za-z_ 但我很好奇。

    澄清: 我不会在regex后面验证类名,也不知道PHP内部是否使用手册中建议的regex。使我困惑的是(显然还有其他相关问题中的人)为什么 $☂ = 1 可以在PHP中使用。php6不支持Unicode版本,但php6处于中断状态。但是如果没有Unicode支持,那我为什么要这样做呢?

    4 回复  |  直到 13 年前
        1
  •  43
  •   Artefacto    13 年前

    这个问题开始在标题中提到类名,但接下来是一个例子,其中包括方法、常量、变量和字段的外来名称。实际上,这些规则是不同的。让我们从不区分大小写的开始。

    不区分大小写的标识符(类和函数/方法名)

    这里的一般准则是只使用可打印的ASCII字符。原因是这些标识符被规范化为它们的小写版本,但是,这种转换依赖于区域设置。考虑以下用ISO-8859-1编码的PHP文件:

    <?php
    function func_á() { echo "worked"; }
    func_Á();
    

    这个剧本行吗?也许吧。这取决于什么 tolower ( 193 ) 将返回,这取决于区域设置:

    $ LANG=en_US.iso88591 php a.php
    worked
    $ LANG=en_US.utf8 php a.php
    
    Fatal error: Call to undefined function func_Á() in /home/glopes/a.php on line 3
    

    因此,使用非ASCII字符不是一个好主意。然而,在某些地区,即使是ASCII字符也会带来麻烦。见 this discussion . 这很可能在将来通过执行一个只与ASCII字符一起工作的独立于区域设置的小写来解决。

    总之,如果我们对这些不区分大小写的标识符使用多字节编码,那么我们就在寻找问题。这不仅仅是因为我们不能利用案例的不敏感性。实际上,我们可能会遇到意外的冲突,因为使用区域设置规则,组成多字节字符的所有字节都会单独转换为小写。在对每个字节应用区域设置小写规则后,两个不同的多字节字符可能映射到相同的修改后的字节流表示形式。

    区分大小写的标识符(变量、常量、字段)

    这里的问题不那么严重,因为这些标识符区分大小写。然而,它们只是被解释为字节流。这意味着如果我们使用Unicode,我们必须一致地使用相同的字节表示;我们不能混合使用utf-8和utf-16;我们也不能使用bom。

    事实上,我们必须坚持使用UTF-8。在ASCII范围之外,utf-8使用从0xc0到0xfd的前导字节,并且跟踪字节在0x80到0xbf范围内,这在手册允许的范围内。现在假设我们在UTF-16BE编码文件中使用字符“_”。这将转换为0x01 0x20,因此第二个字节将被解释为一个空格。

    当然,如果将多字节字符视为单字节字符进行读取,则根本不支持Unicode。PHP 确实有 编译开关形式的一些多字节支持——启用zend multi byte(从php 5.4开始,多字节支持在默认情况下编译,但被禁用;您可以使用 zend.multibyte=On 在php.ini中。这允许你 declare 脚本的编码:

    <?php
    declare(encoding='ISO-8859-1');
    // code here
    ?>
    

    它还将处理用于自动检测编码的BOM,而不会成为输出的一部分。然而,也有一些缺点:

    • 性能命中,内存和CPU。它以内部多字节编码的形式存储脚本的表示,这将占用更多的空间(而且它似乎还将原始版本存储在内存中),并且它还花费一些CPU来转换编码。
    • 多字节支持通常不编译,因此测试较少(错误较多)。
    • 编译了支持的安装与不编译支持的安装之间的可移植性问题。
    • 仅指解析阶段; 不解决 为不区分大小写的标识符列出的问题。

    最后,还有一个问题是缺乏标准化,同一个字符可以用不同的Unicode码位表示(独立于编码)。这可能会导致一些非常难以跟踪的错误。

        2
  •  5
  •   Scharron    14 年前

    您的字符编码为 0x80 0x90 0xe2 或者类似的,因此它在不解释unicode(处理单个字节)时与regexp匹配。

        3
  •  1
  •   Jarsäter    14 年前

    有效的类名以字母或下划线开头,后跟任意数量的字母、数字或下划线。作为正则表达式,它可以这样表示:【a-z a-z_x7f-\xff】【a-z a-z0-9_x7f-\xff】*。

    (来自PHP.NET)

        4
  •  1
  •   webjawns.com    14 年前

    据我所知,当前版本的PHP有一些Unicode支持,但不一致。正如其他人所建议的,这将在php6中解决,而php6被取消(而不是推迟)。一天结束时,一些“异国情调”的角色会起作用,而另一些则不会;显然,正如你所建议的,最好还是坚持下去。 A-Za-z0-9_ .

    同时,我也听说有传言说Unicode的讨论最近重新开始了,大概是从头开始的,因为最初在php6中使用utf-16的提议涉及了大量的工作,几乎没有回报。

    边注: 据我所读,下一个主要的PHP版本将是php 5.4,它可能具有水平集成(traits)、数组速记、内置HTTP服务器和一些其他非常需要的功能。

    http://www.mail-archive.com/internals@lists.php.net/msg35720.html