方法,常量,变量和字段的奇异名称 - 错误还是功能?

2022-08-30 13:09:11

在评论中有些混乱之后

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

澄清:我不追求正则表达式来验证类名,也不知道PHP内部是否使用手册中建议的正则表达式。让我感到困惑的是(显然还有链接问题中的其他人)为什么这样的东西可以在PHP中使用。PHP6 被更新为 Unicode 版本,但 PHP6 处于中断状态。但是,如果没有Unicode支持,那么我为什么要这样做呢?$☂ = 1


答案 1

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

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

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

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

此脚本是否有效?或。这取决于 tolower193 将返回的内容,这与区域设置相关:()

$ 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 字符也可能会带来麻烦。请参阅此讨论。将来可能会通过执行仅适用于 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

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

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

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

最后,存在缺乏规范化的问题 - 相同的字符可以用不同的Unicode码位表示(独立于编码)。这可能会导致一些非常难以跟踪的错误。


答案 2

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


推荐