繁体   English   中英

是否可以动态地向/扩展类添加代码?

[英]Is it possible to dynamically add code to/extend a class?

我想为我的代码编写一种“插件/模块”系统,如果我可以在定义之后将其“添加”到类中,它会更容易。

例如,像这样:

class foo {
  public function a() {
     return 'b';
  }
}

这是班级。 现在我想在定义后添加另一个函数/变量/ const。

我意识到这可能是不可能的,但我需要确认。

不,您无法在运行时向已定义的类添加方法。

但是您可以使用__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";

这个解决方案非常有限,但它可能适合您

要添加/更改类在运行时的行为方式,您应该使用装饰器和/或策略。 这是首选的OO方法,而不是采用任何魔术方法或猴子修补。

装饰器包装类的实例并提供与该实例相同的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;
    }
    // …
}

对于策略,请参阅我的更完整的示例我可以将代码包含到PHP类中吗?

更多细节和示例代码可以在

我有几种方法供您尝试。 :)玩得开心编码。

只有一个类的方法:

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.

注意:

我目前正在使用第一种方法(我只有一个类,mods是例外)在我自己的CMS中,我从头开始(http://sitegen.com.au),它工作得很好,我需要的理由这是因为我已经生成了我的main_class,在我需要./mods-enabled / *创建函数和改变其他函数的工作方式的所有mod之后,我还会再次回到这里,为两个mod提供两个mod的解决方案在没有获胜的情况下更改功能,因为它首先运行。 我将我的插件拆分为两个,在每个站点上运行的mod,以及具有站点设置的插件,甚至可能都没有启用。
玩得开心。

如果它不够神奇,您可以使用动态对象。 常见的想法是: https//github.com/ptrofimov/jslikeobject

你可以扩展课程

class foo {
  public function a() {
     return 'b';
  }
}

class woo extends foo {
  public function newStuff() {
     $var = $this->a();
     echo $var;
  }
}

通过从woo类扩展foo,foo中的功能可用,同时您还可以在woo中创建新方法。 这是向类添加新功能的最简单方法。

您可以使用PHP的魔术功能来提供对编译时未定义的方法的操作。

这实际上是可能的。 例如:

<?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; 
?>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM