【问题标题】:PHP: How is it possible to rename methods?PHP:如何重命名方法?
【发布时间】:2010-07-31 10:15:25
【问题描述】:

是否可以在运行时重命名 PHP 5.2 中的类方法?是否可以使用反射来做到这一点?

给定:

class Test
{
    public function myMethod()
    {
        echo 'in my method';
    }
}

我希望能够将 myMethod() 重命名为 oldMethod(),以便稍后我这样做:

$test = new Test();
$test->oldMethod(); // in my method
$test->myMethod(); // run time error: method does not exist

【问题讨论】:

  • 你到底想做什么,需要贴一些代码。
  • PHP 运行时[重命名函数]的可能重复项。 ](stackoverflow.com/questions/2846353/…)
  • 你打算通过重命名一个方法来达到什么目的?重命名方法的基本原理是什么? __call() 可能是另一种选择。
  • 这味道。你为什么需要这个?
  • @Gordon:因为我想在类上安装调用事件处理程序,而类不知道它,所以我会知道用户正在调用类中的方法 before i> 这个方法实际上被调用了。

标签: php reflection


【解决方案1】:

来自以下问题的评论:

因为我想在类上安装调用事件处理程序,而类不知道它,所以我会知道用户在实际调用该方法之前从类调用方法。

解决方案:使用装饰器。

class EventDecorator
{
    protected $_instance;
    public function __construct($instance)
    {
        $this->_instance = $instance;
    }
    public function __get($prop)
    {
        printf('Getting %s in %s', $prop, get_class($this->_instance));
        return $this->_instance->$prop;
    }
    public function __set($prop, $val)
    {
        printf('Setting %s with %s in %s',
            $prop, $val, get_class($this->_instance));
        return $this->_instance->$prop = $val;
    }
    public function __call($method, $args)
    {
        printf('Calling %s with %s in %s', 
            $method, var_export($args, TRUE), get_class($this->_instance));

        return call_user_func_array(array($this->_instance, $method), $args);
    }
}

然后你可以将任何类包装进去:

class Foo
{
    public $prop;
    public function doSomething() {}
}

$foo = new EventDecorator(new Foo);
$foo->prop = 'bar'; // Setting prop with bar in Foo    
$foo->prop;         // Getting prop in Foo
$foo->doSomething('something'); 
// Calling doSomething with array (0 => 'something',) in Foo

这可以充实以提供 pre 和 post 钩子。您还可以让装饰器使用Subject/Observer Pattern 并向注册到装饰器的任何其他对象触发事件。上述方法比使用 runkit 对随机方法进行猴子补丁更易于维护和理解。

补充说明:

【讨论】:

  • 唯一的问题是当一个函数需要一个类型并且你不能声明你实现它的接口时......如果你扩展那么任何魔法方法都不会触发......function doSomething(Foo $subject)不会'不接受装饰器。
【解决方案2】:

使用Runkits runkit_method_rename 你可以做到这一点。

【讨论】:

  • 你的意思是这个网址:php.net/manual/en/book.classkit.php我现在正在调查。
  • 安装页面显示“此扩展程序被认为未维护且已失效。”我害怕阅读除此之外的任何内容。
  • 哦,太好了,现在我看到一个大红色警告,上面写着“实验性”(是的,大写)。我想这比不推荐使用的任何东西都要好,因为这可能更容易维护。谢谢!
【解决方案3】:

对于所有问为什么需要这个的人,我有一个非常相似的想法。我的想法是尝试动态重命名整个 PHP 类。在我的情况下,它将用于 IRC 聊天机器人,我可以动态加载和实例化插件,这样我就不需要重新启动机器人并且正常运行时间会很长。这将包括重命名与我将尝试加载的类同名的预加载类,这样就不会发生冲突并且可以正常运行。

例如:

我在 irc.example.com 上运行 $bot

我已经安装了插件 test.php 并且可以正常工作,现在当它加载到内存中时,我可以更改文件 test.php 而无需对 $bot 进行任何更改

所以我更新了 test.php

现在我想让它加载到$bot,但是$bot 里面已经有一个测试加载,如果我再次尝试包含 test.php 会发生冲突

因此,我们运行重命名函数将类 test 重命名为类 test[sha1 of a counter]

然后我们包含'test.php'

$bot->test = new test();

我们有了它,一个更新的测试插件安装并加载到$bot的内存中,无需重新启动。

这都是理论,但在立即以“你为什么需要这个”的态度抨击某人的想法之前,需要考虑一下。

我的意思是,让我们在这里说实话。你是一个超级天才,知道所有关于编程的知识并且知道每个人需要或不需要什么的可能性有多大?

【讨论】:

  • 我认为他们询问用例只是因为真正需要这样做的案例并不多,而 Tom 可能会找到一种比安装实验模块更激进的方法。无论如何,我也想这样做,只是为了检查旧代码中对函数、静态类或对象方法的每次调用,而无需大量更改源代码。
  • 使用Strategy pattern 可以更好地处理您想要实现的目标。见my answer here at StackOverflow for an example
猜你喜欢
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 2016-08-21
  • 1970-01-01
相关资源
最近更新 更多