PHP运行时类修改

Posted

技术标签:

【中文标题】PHP运行时类修改【英文标题】:PHP runtime class modification 【发布时间】:2010-12-08 06:54:03 【问题描述】:

所以我希望能够在运行时添加/删除类方法。在你告诉我这是糟糕的 oop 练习之前,它可能是,但我并不在乎。我希望能够做到这一点的原因是因为我希望应用程序非常模块化,因此某些插件可以扩展一些基类并向其添加方法而不会杀死主应用程序。

例如,假设我有以下课程:

class User 
    protected $Id;
    protected $Name;
    protected $Password;
    protected $PostsPerPage;
 

并且说,一些插件增加了用户更改其可见性设置的可能性,向类添加了 $Visible 属性。该类将变为:

class User 
    protected $Id;
    protected $Name;
    protected $Password;
    protected $PostsPerPage;
    protected $Visible;
 

这可以通过 __get 和 __set 来实现,但最常见的实现是获取和设置运行时生成的属性,并且为每个添加的属性编写伪 getter 和 setter 以及使用 __set 会很麻烦在我看来,这是一个禁忌。

我的另一个想法是将用户设置单独存储在另一个数组中,例如 $UserVisiblitySettings[userid],但这使得事情不像我希望的那样 OO。

下一个想法是创建一个辅助类,如下所示:

class UserHelper 
    public function SetVisiblity($user_object,value);

然后,我可以使用 __get 和 __set 来实现“朋友”方法/类,但这听起来太老套了。如果我要那样做,还不如重载 __call、__get 和 __set。此外,我不太确定这是一种好的 OOP 做法,而且看起来也很丑。

我的最后一个想法是使用 eval() 在运行时动态创建类的函数(这也是我能想到的唯一有效的 eval 用法)。基本上,从文件中获取类定义,做一些简单的括号查找来找到类的开始和结束括号并将其发送到 eval。

使用runkit是没有问题的,因为它已经过时了,我不想强​​迫用户安装一些扩展。

当我查看我的想法时,最简单且 CPU 密集度较低的方法似乎是重载 _call 并添加一种在类中注册方法的方法。

请感谢任何不是“不要这样做”的想法。

【问题讨论】:

本质上,您正在寻找 ruby​​ 的扩展/包含机制 (ruby-doc.org/core/classes/Object.html#M000335) 或(在某种程度上)C# 的扩展方法 (msdn.microsoft.com/en-us/library/bb383977.aspx) 的对应物? 和C#的扩展方法一模一样 【参考方案1】:

php 不允许这样做。在其他方面它可能是一种动态语言,但类系统是故意限制的。您可以安装 runkit 扩展,它会更改语言以允许在运行时模拟类(但是您不再使用普通 PHP),或者您可以使用 magic-methods 来模拟它。

【讨论】:

【参考方案2】:

RunKit分机可以做到(runkit_method_add()等)

然而,这是一个实验性的扩展,你已经瞄准了你的脚......

您还有其他选择:

使用__get()__call() 模拟新字段和方法 使用子类化和工厂模式(class Plugin extends BaseImplementation 并让工厂实例化 Plugin 而不是 BaseImplementation)。 Zend Plugin Loader 会做这样的事情。 这是开销最少的解决方案,但也仅限于一个插件扩展一个类。 添加挂钩并使用委托(策略模式)($this->plugin->onFoo())。 There's library for this。

【讨论】:

我相信工厂方法有一些我现在不记得的限制。我会尝试任何一种方式。 工厂解决方案仅限于一个插件扩展一个类。如果您需要任意数量的插件,请使用诸如stickleback 之类的东西。 将 __call 与定位器模式结合使用,我发现在这种情况下非常有用。这里有一个例子:github.com/treshugart/EuropaPHP/tree/master/lib/Europa/….【参考方案3】:

您可以覆盖该类,但我不知道您是否可以在同一个请求中重新加载它。 使用中介设计模式(symfony 事件调度器)可以实现一些行为改变,但您需要提前了解扩展点,并在未来触发事件/消息以被扩展类捕获。

如果你可以等待下一个请求,如果你有它,清除缓存。我制作了一个可以帮助你的工具。 SourceEditor

这里也有类似问题的更多答案,我在其中放置了代码示例。 How to generate or modify a PHP class at runtime?

【讨论】:

以上是关于PHP运行时类修改的主要内容,如果未能解决你的问题,请参考以下文章

通过反射来创建对应运行时类的对象

通过反射来获取对应运行时类的完整结构

Java 反射--创建运行时类的对象

JAVA 创建运行时类实例

反射2.0

Java 反射之调用运行时类中指定的属性