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

Php 是否可以动态地向类添加代码/扩展类?,php,Php,我想为我的代码编写一种“插件/模块”系统,如果我能在定义了类之后将其“添加”到类中,这会变得更容易 例如,类似这样的内容: class foo { public function a() { return 'b'; } } 这是我的班级。现在,我想在它定义之后,向它添加另一个函数/变量/常量 我意识到这可能是不可能的,但我需要确认。您可以扩展该类 class foo { public function a() { return 'b'; } } class

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

例如,类似这样的内容:

class foo {
  public function a() {
     return 'b';
  }
}
这是我的班级。现在,我想在它定义之后,向它添加另一个函数/变量/常量


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

您可以扩展该类

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

否,您不能在运行时将方法添加到已定义的类中

但是您可以使用
\uuuu call/\uuuu 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;
    }
    // …
}
有关策略,请参阅我在

有关更多详细信息和示例代码,请访问


    • 我有一些方法供您尝试。:)享受编码的乐趣

      仅用于一个类的方法: 要处理多个类时的方法: 现在让我们尝试使用它们: 注: 我目前正在我自己的CMS中使用第一种方法(我只有一个类,mods是例外),这是我从头开始制作的(http://sitegen.com.au),而且效果很好,我之所以需要这样做,是因为我需要在./mods enabled/*中创建所有mod并更改其他函数的工作方式后,生成了我的主_类。我还将再次回到这里,提供一个解决方案,两个mod都可以更改一个函数,但没有一个mod在第一次运行时获胜。我将插件分为两部分,一部分是在每个站点上运行的MOD,另一部分是为某个站点设置的插件,甚至可能无法启用。

      享受编程乐趣。

      如果对你来说还不够神奇,你可以使用动态对象。这里有一个共同的想法:

      你能告诉我你所说的定义是什么吗?你的意思是文件已经包括在内,但没有对象被初始化,还是有对象被初始化?我想我在irc.freenode.net上见过你,你注册了吗?还是有人偷了你的freenode在线别名?@JamesM SiteGen是的。那应该是我。你好,你喜欢我的答案吗?小而简单。:)看到了,很好的解决方案/讨论指向,但是我必须在我的课堂上使用woo类,而不是foo,对吗?你必须通过woo而不是foo来使用你添加的功能。基本上,您可以保持foo类不变,但可以通过从不同的其他类扩展它来添加不同的功能。如果你不知道你想让你的代码做什么,就很难给出对你有用的确切例子。我想更多地添加函数和常量之类的东西。我应该在我的作品中这样说…这在什么方面是有限的?我能看到这种限制的唯一方式可能是无法添加受保护的方法。
      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.