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

mar*_*rio 31 php namespaces tokenize

我正在尝试自动从PHP类集合中删除命名空间,以使它们与PHP 5.2兼容.(共享主机提供商并不喜欢流氓PHP 5.3安装.不知道为什么.此外,有问题的代码不使用任何5.3功能添加,只是语法.自动转换似乎比手动或重新实现代码库更容易.)

为了重写*.php脚本,我基本上是在一个tokenizer列表上运行.标识符搜索+合并已经完成.但是我现在有点困惑如何完成实际的重写.

function rewrite($name, $namespace, $use) {

    global $identifiers2;            // list of known/existing classes

    /*
        bounty on missing code here
    */

    return strtr($name, "\\", "_");  // goal: backslash to underscore
}
Run Code Online (Sandbox Code Playgroud)

将在每个找到的标识符(无论是类,函数还是常量)上调用该函数.它将接收一些上下文信息,以将本地标识符转换为绝对/全局$ name:

$name =
    rewrite(
        "classfuncconst",      # <-- foreach ($names as $name)
        "current\name\space",
        array(
           'namespc' => 'use\this\namespc',
           'alias' => 'from\name\too',
           ...
        )
    );
Run Code Online (Sandbox Code Playgroud)

在这个阶段,我已经准备了$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)
Run Code Online (Sandbox Code Playgroud)

函数$name接收的参数rewrite()可以是本地的,非限定的,\ absolutename\spaced标识符(但只是标识符,没有表达式).该$identifiers2列表对于解析非限定标识符至关重要,这些标识符可以引用当前命名空间中的内容,或者如果没有在那里找到全局内容.

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

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

精神懒惰赏金.

为了使这个问题变得不那么明显:一个解释性指令列表或伪代码答案也是合格的.如果另一种方法更适合这项任务,请详细说明.(但不,升级PHP或更改主机不是一种选择.)

我想我已经明白了,但问题仍然是答案/实施建议.(否则赏金显然会转向nikic.)

Nik*_*kiC 18

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

你会发现我实现的命名空间- >在伪命名空间分辨率namespace.php.我基于命名空间解析规则的实现,这可能对你有所帮助.

为了使这个不那么明显的readmycodez答案,这里代码的基本步骤:

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

附加说明:不要忘记也可以写namespace\some\ns.我解决这些结构NS功能(这也是负责寻找命名空间声明).

  • 非常有趣.看起来这几乎是一个解决的任务.由于您的实施非常清晰,如果我无法让我的工作,我会使用它.你已经解决了lambda函数问题.(在令牌列表上工作确实只会使问题复杂化,但至少它可以通过一些让步来实现.) - 全局函数/类歧义可能是一个问题,这也是我尝试$ identifier2列表解决方法的原因. (2认同)