PHP运行时类修改
因此,我希望能够在运行时添加/删除类方法。在你告诉我这在oop中是可怕的做法之前,也许是,但我真的不在乎。我之所以希望能够做到这一点,是因为我希望应用程序是非常模块化的,因此一些插件可以扩展一些基类并向其中添加方法,而不会杀死主应用程序 例如,假设我有以下课程:PHP运行时类修改,php,oop,reflection,class,dynamic,Php,Oop,Reflection,Class,Dynamic,因此,我希望能够在运行时添加/删除类方法。在你告诉我这在oop中是可怕的做法之前,也许是,但我真的不在乎。我之所以希望能够做到这一点,是因为我希望应用程序是非常模块化的,因此一些插件可以扩展一些基类并向其中添加方法,而不会杀死主应用程序 例如,假设我有以下课程: class User { protected $Id; protected $Name; protected $Password; protected $PostsPerPage; } 比如说,一些插
class User {
protected $Id;
protected $Name;
protected $Password;
protected $PostsPerPage;
}
比如说,一些插件增加了用户更改可见性设置的可能性,向类中添加了$Visible属性。课程将变成:
class User {
protected $Id;
protected $Name;
protected $Password;
protected $PostsPerPage;
protected $Visible;
}
这可以通过uuu get和uu set来实现,但最常见的实现是获取和设置运行时生成的属性,为每个添加的属性编写伪getter和setter会很麻烦,而且在我看来,使用u set是不可能的
我的另一个想法是将用户设置单独存储在另一个数组中,如$UserVisiblitySettings[userid],但这并不像我希望的那样是面向对象的
下一个想法是创建一个helper类,如下所示:
class UserHelper {
public function SetVisiblity($user_object,value);
}
然后,我可以使用uuuu get和uuu set来实现“friend”方法/类,但这听起来太粗糙了。如果我走那条路的话,还不如打个超负荷的电话,接个电话就可以了。我也不太确定这是不是一个好的OOP实践,它看起来也很难看
我的最后一个想法是使用eval()在运行时使用一些函数动态创建类(这也是我能想到的eval的唯一有效用法)。基本上,从文件中获取类定义,进行一些简单的括号查找,找到类的开始括号和结束括号,并将其发送给eval
使用runkit是不可能的,因为它已经过时了,我不想强迫用户安装一些扩展
当我回顾我的想法时,最简单、cpu占用较少的方法似乎是重载调用,并添加一种在类中注册方法的方法
请注意,任何不是“不要这样做”的想法都将受到赞赏。PHP不允许这样做。在其他方面,它可能是一种动态语言,但类系统是故意限制的。您可以安装扩展,该扩展更改了语言以允许在运行时对类进行模拟(但是您不再使用普通PHP),也可以使用来模拟它。扩展可以做到这一点(
runkit\u method\u add()
,等等)
然而,这是一个实验性的扩展,你已经瞄准了你的脚
您还有其他选择:
- 使用
和\uu get()
\uu call()
- 使用子类化和工厂模式(
并让工厂实例化classpluginextensedbaseimplementation
,而不是Plugin
)。Zend Plugin Loader可以执行类似的操作。BaseImplementation
它是开销最小的解决方案,但也仅限于扩展一个类的一个插件 - 添加挂钩并使用委派(策略模式)(
)李>$this->plugin->onFoo()
- 您可以重写该类,但我不知道您是否可以在同一请求中重新加载它。
使用中介器设计模式(symfony event dispatcher)可以实现一些行为更改,但您需要提前知道扩展点,并在将来触发扩展类将捕获的事件/消息
如果可以等待下一个请求,请清除缓存(如果有的话)。我做了一个可能对你有帮助的工具。
这里也有类似问题的更多答案,我在这里放了一些代码示例。
本质上,您正在寻找ruby的extend/include机制()或(某种程度上)C#的扩展方法()的对应物?与C#的扩展方法一模一样。我相信工厂方法有一些限制,我现在记不起来了。我会尝试任何一种方法。工厂解决方案仅限于扩展一个类的一个插件。如果您需要任意数量的插件,请使用stickleback之类的方法。使用_调用结合定位器模式,我发现在这种情况下非常有用。这里有一个例子:。