沃梦达 / 编程问答 / php问题 / 正文

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

PHP namespace removal / mapping and rewriting identifiers(PHP 命名空间移除/映射和重写标识符)

本文介绍了PHP 命名空间移除/映射和重写标识符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm attempting to automate the removal of namespaces from a PHP class collection to make them PHP 5.2 compatible. (Shared hosting providers do not fancy rogue PHP 5.3 installations. No idea why. Also the code in question doesn't use any 5.3 feature additions, just that syntax. Autoconversion seems easier than doing it by hand or reimplementing the codebase.)

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

For rewriting the *.php scripts I'm basically running over a tokenizer list. The identifier searching+merging is already complete. But I'm a bit confused now how to accomplish the actual rewriting.

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:

That function is going to be invoked on each found identifier (whether class, function or const). It will receive some context information to transform a local identifier into an absolute/global $name:

$name =
    rewrite(
        "classfuncconst",      # <-- foreach ($names as $name)
        "current
amespace",
        array(
           'namespc' => 'use	his
amespc',
           'alias' => 'from
ame	oo',
           ...
        )
    );

在这个阶段,我已经准备了一个 $identifiers2 列表.它包含所有已知类、函数和常量名称的列表(为简单起见在此合并).

At this stage I've already prepared an $identifiers2 list. It contains a list of all known classes, functions and constant names (merged for simplicity here).

$identifiers2 = array(             // Alternative suggestions welcome.
   "namespaceClass" => "Class",  // - list structure usable for task?
   "other
sfunc1" => "func1",    // - local name aliases helpful?
   "blipCONST" => "CONST",        // - (ignore case-insensitivity)

rewrite() 函数接收到的 $name 参数可以是 localunqualifiedabsolutenamespaced 标识符(但只是标识符,没有表达式).$identifiers2 列表对于解析 unqualified 标识符至关重要,这些标识符可以引用当前命名空间中的事物,或者如果在那里找不到,则为全局事物.

The $name parameter as received by the rewrite() function can be a local, unqualified, absolute or namespaced identifier (but just identifers, no expressions). The $identifiers2 list is crucial to resolve unqualified identifiers, which can refer to things in the current namespace, or if not found there, global stuff.

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

And the various use namespace aliases have to be taken into account and add some complication besides the namespace resolving and precedence rules.

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

So, how / in which order would you attempt to convert the variations of class/function names here?

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

Mental Laziness Bounty.

To make this a less blatant plzsendtehcodez question: an explainative instruction list or pseudo-code answer would be eligible too. And if another approach would be more suitable for the task, please elaborate on that rather. (But no, upgrading PHP or changing the hoster is not an option.)

我想我已经想通了,但问题仍然有待回答/实施建议.(否则赏金显然会归 nikic.)

I think I've figured it out meanwhile, but the question is still open for answers / implementation proposals. (Otherwise the bounty will obviously go to nikic.)

推荐答案

在 关于将命名空间迁移到伪命名空间代码的现有问题 我已经 引入了一个转换工具我写的一个更大的项目.从那时起我就不再维护这个项目了,但据我所知,命名空间替换确实有效.(我可能会在某个时候使用 适当的解析器 重新实现这个项目.使用纯令牌已被证明这是一项相当乏味的任务.)

In an existing question on migration of namespaces to pseudo namespaced code I already introduced a conversion tool I have written as part of a larger project. I haven't maintained this project anymore since that point, but as far as I remember the namespace replacements did work. (I may reimplement this project using a proper parser at some point. Working with plain tokens has proven to be quite a tedious task.)

您将在 伪命名空间解析的实现="nofollow noreferrer">namespace.php.我的实现基于 命名空间解析规则,它将可能对你也有帮助.

You will find my implementation of namespace -> pseudo-namespace resolution in the namespace.php. I based the implementation on the namespace resolution rules, which will probably be of help for you, too.

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

To make this a less blatant readmycodez answer, here the basic steps the code does:

  1. 获取要解析的标识符,并确保它不是类、接口、函数或常量声明(这些在registerClass 和 registerOther 只需在当前命名空间前加上 ns 分隔符替换为下划线).
  2. 确定它是什么类型的标识符:类、函数或常量.(因为这些需要不同的分辨率.)
  3. 确保我们不解析 selfparent 类,也不解析 truefalsenull 常量.
  4. 解析别名(使用列表):
  1. Get the identifier to be resolved and ensure that it is not a class, interface, function or constant declaration (these are resolved in registerClass and registerOther by simply prepending the current namespace with ns separators replaced by underscores).
  2. Determine what type of identifier it is: A class, a function or a constant. (As these need different resolution.)
  3. Make sure we do not resolve the self and parent classes, nor the true, false and null constants.
  4. Resolve aliases (use list):
  1. 如果标识符是合格的,则获取第一个命名空间分隔符之前的部分,并检查是否存在具有该名称的别名.如果是这样,用别名命名空间替换第一部分(现在标识符将是完全限定的).否则添加当前命名空间.
  2. 如果标识符不合格且标识符类型为class,则检查标识符是否为别名,如果是,则将其替换为别名类.
  1. If the identifier is qualified get the part before the first namespace separator and check whether there exists an alias with that name. If it does, replace the first part with the aliased namespace (now the identifier will be fully qualified). Otherwise prepend the current namespace.
  2. If identifier is unqualified and the identifier type is class, check whether the identifier is an alias and if it is, replace it with the aliased class.

  • 如果标识符是完全限定的,现在删除前导命名空间分隔符并用下划线替换所有其他命名空间分隔符并结束此算法.
  • 否则:

    1. 如果我们在全局命名空间中,则不需要进一步解析,因此结束此算法.
    2. 如果标识符类型是class,在当前命名空间前添加,用下划线替换所有NS分隔符并结束该算法.
    3. 否则:
    1. If we are in the global namespace no further resolution required, thus end this algorithm.
    2. If the identifier type is class prepend the current namespace, replace all NS separators with underscores and end this algorithm.
    3. Otherwise:
    1. 如果函数/常量是全局定义的,则保持标识符不变并结束此算法.(这假设没有在命名空间中重新定义全局函数!在我的代码中我没有做这个假设,因此我插入了动态解析代码.)
    2. 否则,在当前命名空间前面加上下划线替换所有命名空间分隔符.(好像我的代码有问题:即使设置了 assumeGlobal 标志,我也不这样做.相反,我总是插入动态调度代码.)
    1. If the function / constant is defined globally leave the identifier as is and end this algorithm. (This assumes that no global functions are redefined in a namespace! In my code I don't make this assumption, thus I insert dynamic resolution code.)
    2. Otherwise prepend the current namespace and replace all namespace separators with underscores. (Seems like I got a fault in my code here: I don't do this even if the assumeGlobal flag is set. Instead I always insert the dynamic dispatch code.)

  • 补充说明:别忘了也可以写成namespacesome s.我在 NS function(也负责查找命名空间声明).

    Additional note: Don't forget that one can also write namespacesome s. I resolve these constructs in the NS function (which is also responsible for finding namespace declarations).

    这篇关于PHP 命名空间移除/映射和重写标识符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

    本文标题为:PHP 命名空间移除/映射和重写标识符

    基础教程推荐