PHP 命名空间删除/映射和重写标识符

2022-08-30 14:19:37

我正在尝试从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
}

该函数将在每个找到的标识符(无论是类,函数还是const)上调用。它将接收一些上下文信息,以将本地标识符转换为绝对/全局$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\spaced 标识符(但只是标识器,没有表达式)。该列表对于解析非限定标识符至关重要,这些标识符可以引用当前命名空间中的事物,或者如果找不到,则引用全局内容。$namerewrite()$identifiers2

并且必须考虑各种别名,并且除了命名空间解析和优先级规则之外,还会增加一些复杂性。use namespace

那么,您将如何/以何种顺序尝试在此处转换类/函数名称的变体?

精神懒惰赏金。

为了使这成为一个不那么明目张胆的plzsendtehcodez问题:解释性指令列表或伪代码答案也符合条件。如果另一种方法更适合这项任务,请详细说明这一点。(但是不,升级PHP或更改主机不是一种选择。

我想我同时已经想通了,但这个问题仍然有待回答/实施建议。(否则赏金显然会流向nikic。


答案 1

关于将命名空间迁移到伪命名空间代码的现有问题中,我已经介绍了一个转换工具,该工具是我作为更大项目的一部分编写的。从那时起,我不再维护这个项目,但据我所知,命名空间替换确实有效。(我可能会在某个时候使用适当的解析器重新实现这个项目。使用普通令牌已被证明是一项非常繁琐的任务。

您将在命名空间中找到我对命名空间 -> 伪命名空间解析的实现.php。我基于命名空间解析规则实现,这可能也会对您有所帮助。

为了使这成为一个不那么公然的readmycodez答案,以下是代码执行的基本步骤:

  1. 获取要解析的标识符,并确保它不是类、接口、函数或常量声明(这些在 registerClassregisterOther 中解析,只需在当前命名空间前面加上 ns 分隔符,用下划线替换)。
  2. 确定标识符的类型:类、函数或常量。(因为这些需要不同的分辨率。
  3. 确保我们不解析 和 类,也不解析 和 常量。selfparenttruefalsenull
  4. 解析别名 ( 列表):use
    1. 如果标识符是限定的,则获取第一个命名空间分隔符之前的部件,并检查是否存在具有该名称的别名。如果是这样,请将第一部分替换为别名命名空间(现在标识符将是完全限定的)。否则,请先附加当前命名空间。
    2. 如果标识符是非限定的,并且标识符类型是 ,请检查标识符是否为别名,如果是,则将其替换为别名类。class
  5. 如果标识符是完全限定的,则现在删除前导命名空间分隔符,并将所有其他命名空间分隔符替换为下划线并结束此算法。
  6. 否则:
    1. 如果我们在全局命名空间中,则不需要进一步的解析,因此结束此算法。
    2. 如果标识符类型位于当前命名空间前面,请将所有 NS 分隔符替换为下划线并结束此算法。class
    3. 否则:
      1. 如果函数/常量是全局定义的,则保持标识符不变并结束此算法。(这假设在命名空间中没有重新定义任何全局函数!在我的代码中,我不做这个假设,因此我插入了动态解析代码。
      2. 否则,请先附加当前命名空间,并将所有命名空间分隔符替换为下划线。(似乎我在这里的代码中有一个错误:即使设置了标志,我也不会这样做。相反,我总是插入动态调度代码。assumeGlobal

附加说明:不要忘记,也可以写.我在 NS 函数(也负责查找命名空间声明)中解析这些构造。namespace\some\ns


答案 2

推荐