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

时间:2011-01-12 12:32:03

标签: php

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

例如,像这样:

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

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

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

7 个答案:

答案 0 :(得分:5)

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

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

此解决方案非常有限,但可能适用于您

答案 1 :(得分:3)

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

Decorator包装类的实例并提供与该实例相同的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?

上的更完整示例

可以在

找到更多详细信息和示例代码

答案 2 :(得分:1)

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

只有一个类的方法:

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.

注意:

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

答案 3 :(得分:0)

您可以扩展课程

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

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

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

答案 4 :(得分:0)

您可以使用PHP的magic functionality来为在编译时未定义的方法提供操作。

答案 5 :(得分:0)

实际上是可能的。例如:

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

答案 6 :(得分:0)

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