方法,常量,变量和字段的异域名称 - Bug还是Feature?

时间:2010-08-05 17:00:11

标签: php unicode

之后对评论中的一些混淆

我以为我提出了一个问题。根据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 个答案:

答案 0 :(得分:43)

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

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

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

<?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 确实具有编译开关“--enable-zend-multibyte”形式的一些多字节支持(从PHP 5.4开始,多字节支持默认编译,但已禁用;您可以在php.ini中使用zend.multibyte=On启用它。这允许您declare脚本的编码:

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

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

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

最后,存在缺乏规范化的问题 - 相同的字符可以用不同的Unicode代码点表示(与编码无关)。这可能会导致一些非常难以追踪的错误。

答案 1 :(得分:5)

您的角色被编码为0x80 0x90 0xe2或类似的东西,因此它在不解释unicode(处理单个字节)时与正则表达式匹配。

答案 2 :(得分:1)

有效的班级名称以字母或下划线开头,后跟任意数量的字母,数字或下划线。作为正则表达式,它将表示为:[a-zA-Z_ \ x7f- \ xff] [a-zA-Z0-9_ \ x7f- \ xff] *。

(来自php.net)

答案 3 :(得分:1)

据我了解,当前版本的PHP有一些unicode支持,但它不一致。正如其他人所建议的那样,这将在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