我希望为我的代码编写一种“插件/模块”系统,如果我能在定义类之后“添加”东西到一个类中,那将会使这个过程更加容易。例如,像这样的东西:
class foo {
public function a() {
return 'b';
}
}
这是一个类。现在我想在它定义之后向其添加另一个函数/变量/常量。
我意识到这可能不可能,但我需要确认。
class foo {
public function a() {
return 'b';
}
}
这是一个类。现在我想在它定义之后向其添加另一个函数/变量/常量。
我意识到这可能不可能,但我需要确认。
不,你不能在运行时向已定义的类中添加方法。
但是你可以使用__call/__callStatic
魔术方法创建类似的功能。
Class Extendable {
private $handlers = array();
public function registerHandler($handler) {
$this->handlers[] = $handler;
}
public function __call($method, $arguments) {
foreach ($this->handlers as $handler) {
if (method_exists($handler, $method)) {
return call_user_func_array(
array($handler, $method),
$arguments
);
}
}
}
}
Class myclass extends Extendable {
public function foo() {
echo 'foo';
}
}
CLass myclass2 {
public function bar() {
echo 'bar';
}
}
$myclass = new myclass();
$myclass->registerHandler(new myclass2());
$myclass->foo(); // prints 'foo'
echo "\n";
$myclass->bar(); // prints 'bar'
echo "\n";
要在运行时添加/更改类的行为,应使用装饰器和/或策略模式。这是优选的面向对象方法,而不是采用任何神奇的方法或猴子补丁。
装饰器包装一个类的实例,并提供与该实例相同的API。任何调用都被委托给包装的实例,并根据需要修改结果。
class Decorator
{
// …
public function __construct($decoratedInstance)
{
$this->_decoratedInstace = $decoratedInstance;
}
public function someMethod()
{
// call original method
$result = $this->_decoratedInstance->someMethod();
// decorate and return
return $result * 10;
}
// …
}
关于策略模式,您可以参考我在Can I include code into a PHP class?中提供的更完整的示例。
更多细节和示例代码可在以下链接找到:
我有几个方法供你尝试。:) 祝你编程愉快。
class main_class {
private $_MODS = array(),...;
public ...;
public function __construct(...) {
...
global $MODS_ENABLED;
$this -> $_MODS = $MODS_ENABLED;
}
...
public function __get( $var ) {
foreach ( $this->_MODS as $mod )
if ( property_exists( $mod, $var ) )
return $mod -> $var;
}
public function __call( $method, $args ) {
foreach ( $this->_MODS as $mod )
if ( method_exists( $mod, $method ) )
return call_user_method_array( $method, $mod, $args );
}
}
class modMe {
private $_MODS = array();
public function __construct__() {
global $MODS_ENABLED;
$this -> $_MODS = $MODS_ENABLED;
}
public function __get( $var ) {
foreach ( $this->_MODS as $mod )
if ( property_exists( $mod, $var ) )
return $mod -> $var;
}
public function __call( $method, $args ) {
foreach ( $this->_MODS as $mod )
if ( method_exists( $mod, $method ) )
return call_user_method_array( $method, $mod, $args );
}
}
class mainClass extends modMe {
function __construct(...){
$this -> __construct__();
}
}
$MODS_ENABLED = array();
$MODS_ENABLED[] = new mod_mail();
$myObj = new main_class(...);
$myObj -> mail("me@me.me","you@you.you","subject","message/body","Extra:Headers;More:Headers");
# Hey look, my mail class was just added into my main_class for later use.
我目前正在使用第一种方法(我只有一个类,mod是例外)在我自己从头开始制作的 CMS(http://sitegen.com.au)中,并且它运行良好。我需要这个的原因是,我有一个 main_class,在我要求./mods-enabled/* 中的所有 mod 之后生成,创建函数并更改其他函数的工作方式。我还会回来,提供一个解决方案,使两个 mod 都可以更改一个函数,而不是先运行的那个获胜。我把我的插件分成了两部分:在每个站点上运行的 mod 和具有站点设置并且甚至可能未启用的插件。
祝编程愉快。
class foo {
public function a() {
return 'b';
}
}
class woo extends foo {
public function newStuff() {
$var = $this->a();
echo $var;
}
}
这是完全可能的。例如:
<?php
class Test {
function set($set, $val) {
$this->$set = $val;
}
function get($get) {
return $this->$get;
}
}
$t = new Test();
$t->set('hello', 'world');
echo $t->get('hello');
exit;
?>