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

时间:2011-05-23 23:49:17

标签: 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
}

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

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

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

  

精神懒惰赏金。

     

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

     

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

1 个答案:

答案 0 :(得分:18)

existing question on migration of namespaces to pseudo namespaced code我已经introduced a conversion tool我已经写了一个大项目的一部分。从那时起我就不再维护这个项目,但据我记得,命名空间替换确实有效。 (我可能会在某个时候使用proper parser重新实现这个项目。使用普通令牌已经证明是一项相当繁琐的工作。)

你会发现我的命名空间实现 - &gt; namespace.php中的伪命名空间解析。我的实施基于namespace resolution rules,这也可能对你有所帮助。

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

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