提问人:mario 提问时间:5/24/2011 最后编辑:mario 更新时间:8/4/2011 访问量:4360
PHP 命名空间删除/映射和重写标识符
PHP namespace removal / mapping and rewriting identifiers
问:
我正在尝试从 PHP 类集合中自动删除命名空间,以使它们与 PHP 5.2 兼容。(共享主机提供商不喜欢流氓 PHP 5.3 安装。不知道为什么。此外,有问题的代码没有使用任何 5.3 功能添加,只是使用该语法。自动转换似乎比手动操作或重新实现代码库更容易。
为了重写 *.php 脚本,我基本上是在运行一个分词器列表。标识符搜索+合并已经完成。但是我现在有点困惑如何完成实际的重写。
function rewrite($name, $namespace, $use) {
global $identifiers2; // list of known/existing classes
/*
bounty on missing code here
*/
return strtr($name, "\\", "_"); // goal: backslash to underscore
}
该函数将在每个找到的标识符(无论是类、函数还是常量)上调用。它将接收一些上下文信息,以将本地标识符转换为绝对/全局$name:
$name =
rewrite(
"classfuncconst", # <-- foreach ($names as $name)
"current\name\space",
array(
'namespc' => 'use\this\namespc',
'alias' => 'from\name\too',
...
)
);
在这个阶段,我已经准备了一个清单。它包含所有已知类、函数和常量名称的列表(为简单起见,此处合并)。$identifiers2
$identifiers2 = array( // Alternative suggestions welcome.
"name\space\Class" => "Class", // - list structure usable for task?
"other\ns\func1" => "func1", // - local name aliases helpful?
"blip\CONST" => "CONST", // - (ignore case-insensitivity)
函数接收的参数可以是本地的、非限定的、\绝对的或名称\间隔的标识符(但只是标识符,没有表达式)。该列表对于解析非限定标识符至关重要,这些标识符可以引用当前命名空间中的内容,或者如果找不到,则引用全局内容。$name
rewrite()
$identifiers2
并且必须考虑各种别名,除了命名空间解析和优先级规则之外,还增加了一些复杂性。use namespace
那么,您将如何/以何种顺序尝试在此处转换类/函数名称的变体?
精神懒惰赏金。
为了使这个问题不那么明目张胆:解释性指令列表或伪代码答案也符合条件。如果另一种方法更适合这项任务,请详细说明。(但是不可以,升级 PHP 或更改主机不是一种选择。
我想我已经想通了,但这个问题仍然有待回答/实施建议。(否则赏金显然会归尼基奇所有。
答:
在关于将命名空间迁移到伪命名空间代码的现有问题中,我已经介绍了一个转换工具,该工具是作为更大项目的一部分编写的。从那时起,我就不再维护这个项目了,但据我所知,命名空间替换确实有效。(我可能会在某个时候使用适当的解析器重新实现这个项目。事实证明,使用普通令牌是一项相当繁琐的任务。
您将在 namespace.php中找到我的 namespace -> 伪命名空间解析的实现。我基于命名空间解析规则实现,这可能也会对您有所帮助。
为了使这成为一个不那么明目张胆的 readmycodez 答案,以下是代码执行的基本步骤:
- 获取要解析的标识符,并确保它不是类、接口、函数或常量声明(这些在 registerClass 和 registerOther 中解析,只需在当前命名空间前面加上 ns 分隔符替换为下划线)。
- 确定标识符的类型:类、函数或常量。(因为这些需要不同的分辨率。
- 确保我们不解析 和 类,也不解析 、 和 常量。
self
parent
true
false
null
- 解析别名(列表):
use
- 如果标识符是限定的,请获取第一个命名空间分隔符之前的部分,并检查是否存在具有该名称的别名。如果是这样,请将第一部分替换为别名命名空间(现在标识符将完全限定)。否则,在当前命名空间前面添加。
- 如果 identifier 为非限定且标识符类型为 ,请检查标识符是否为别名,如果是,则将其替换为别名类。
class
- 如果标识符是完全限定的,现在删除前导命名空间分隔符,并将所有其他命名空间分隔符替换为下划线,然后结束此算法。
- 否则:
- 如果我们在全局命名空间中,则不需要进一步的解析,因此结束此算法。
- 如果标识符类型在当前命名空间前面加上,请将所有 NS 分隔符替换为下划线并结束此算法。
class
- 否则:
- 如果函数/常量是全局定义的,则保持标识符不变并结束此算法。(这假设在命名空间中没有重新定义全局函数!在我的代码中,我没有做出这个假设,因此我插入了动态解析代码。
- 否则,在当前命名空间前面加上所有命名空间分隔符,并将所有命名空间分隔符替换为下划线。(似乎我在这里的代码中出现了错误:即使设置了标志,我也不会这样做。相反,我总是插入动态调度代码。
assumeGlobal
附加说明:别忘了也可以写 .我在 NS
函数(该函数还负责查找命名空间声明)中解析这些构造。namespace\some\ns
评论
$use["namespace"] = $namespace;
评论