【问题标题】:Is it possible to replace (monkeypatch) PHP functions?是否可以替换(monkeypatch)PHP 函数?
【发布时间】:2010-10-06 13:11:58
【问题描述】:

你可以在 Python 中做到这一点,但在 PHP 中可以吗?

>>> def a(): print 1
... 
>>> def a(): print 2
... 
>>> a()
2

例如:

<? function var_dump() {} ?>
Fatal error: Cannot redeclare var_dump() in /tmp/- on line 1

【问题讨论】:

    标签: php function monkeypatching


    【解决方案1】:

    不,不可能像您期望的那样做到这一点。

    来自manual

    PHP 不支持函数重载,也不能取消定义或重新定义以前声明的函数。

    但是,您可以使用runkit_function_redefine 及其表兄弟,但它绝对不是很优雅...

    你也可以使用create_function 来做这样的事情:

    <?php
    $func = create_function('$a,$b','return $a + $b;');
    echo $func(3,5); // 8
    $func = create_function('$a,$b','return $a * $b;');
    echo $func(3,5); // 15
    ?>
    

    与 runkit 一样,它不是很优雅,但它提供了您正在寻找的行为。

    【讨论】:

    • 你说了两遍,为什么“不太优雅”?
    • @Pacerier:嗯,对于初学者来说,一开始就想做这件事有点代码味道,而且肯定会让任何在你身后看到你的人望而却步代码,但是如果你过去了,在这两种情况下都必须将函数代码作为字符串参数输入,这对于除了最短的函数之外的任何东西都是难看的。
    • 当然我们至少在 PHP 5.3 上,没有人再做 String,函数代码可以作为匿名函数提供。
    • @Pacerier:我从来没有使用过这个函数,这个答案是 6 年前写的,我不太关心它,但手册说只有一个字符串被接受为一个论据。不过,匿名函数可以/应该用于解决 >5.3 中的类似问题。
    【解决方案2】:

    【讨论】:

    • 链接已失效。
    【解决方案3】:

    我意识到这个问题有点老了,但Patchwork 是最近发布的一个支持重新定义用户定义函数的 PHP 5.3 项目。不过,正如作者所提到的,您需要使用 runkitphp-test-helpers 来使用猴子补丁核心/库功能。

    【讨论】:

    • 非常好的小库。感谢分享:)
    【解决方案4】:

    正如 jmikola 所说,如果您想向函数添加代码,Patchwork 是一个很好的解决方案。

    这是一篇关于它如何工作的文章: http://phpmyweb.net/2012/04/26/write-an-awesome-plugin-system-in-php/

    它带有一些示例代码。我认为phpmyweb版本使用了稍微好一点的代码,因为他不使用eval()的代码,不像patchwork。使用 eval() 时可以缓存操作码。

    【讨论】:

    • 为什么在进行单元测试时需要担心操作码缓存?或者什么...您正在使用猴子补丁进行测试以外的其他事情?在这种情况下,您需要担心比eval() 更大的问题。
    • @Spudley 显然我发布的文章不是针对单元测试的(因此标题为“编写一个很棒的插件系统”)。他只是展示了另一种创建插件架构的方法。他还说他只是想展示另一种创建这种架构的方式。当然,如果它是一个好方法,这是有待商榷的。虽然我看不出有什么问题。 --- 你在说什么“问题”?正如作者所说,操作码缓存应该不是问题,因为根本不使用 eval()(不像拼凑)。
    • @Vivendi,patchwork 是否在内部使用 runkit 函数?
    • @Pacerier 不,它使用streamWrapper 类。有了它,您基本上可以在 PHP 解释器解析包含的源文件之前重写它们。
    • @Vivendi,为什么会写成"This is NOT a real class"
    【解决方案5】:

    这有点晚了,但我只想指出,从 PHP 5.3 开始,实际上可以在不使用 PHP 扩展的情况下覆盖内部函数。

    诀窍是您可以在命名空间内重新定义内部 PHP 函数。它基于 PHP 对函数进行名称解析的方式:

    在命名空间内(比如 A\B),对不合格函数的调用在运行时被解析。以下是对函数 foo() 的调用是如何解决的:

    1. 它从当前命名空间中寻找一个函数:A\B\foo()。
    2. 它试图找到并调用全局函数 foo()

    【讨论】:

    • 很可能,因为它是在问题发布近四年后发布的,而接受的答案可能是当时最相关的答案。
    • 我还在 SO... 接受!
    【解决方案6】:

    接受的答案非常好!!!我只是补充一点,您可以将您的代码放入Namespace brackets,然后重置默认的 GLOBAL-SPACE。

    其他一些方法:

    1)rename_function($old_name,$new_name)

    2)override_function($old_name, $parameters, $new_func)

    很少使用:

    3)runkit_function_rename(...)

    4)runkit_function_redefine(...)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-11
      相关资源
      最近更新 更多