【问题标题】:Variable variable class extensions in PHP--is it possible?PHP中的变量类扩展——可能吗?
【发布时间】:2010-09-23 04:50:04
【问题描述】:

在 PHP 中是否可能出现以下情况?

$blah = 'foo1';

class foo2 extends $blah {
    //...
}

class foo1 {
    //...
}

这给出了一个错误。

我想动态设置 $blah,这样我就可以扩展我想要的任何类。

编辑:之所以要这样做,是因为我想在相关类中使用另一个类中的函数。最后应该是这样的:

Final extends foo1 extends foo2 extends foo3 extends foo4 extends parent { ... }

最后我决定在类中实例化另一个类并使用它。不是最好的选择,因为他们都是同一类的两个,但这不会经常使用,所以它现在可以工作。

【问题讨论】:

    标签: php class object variable-variables


    【解决方案1】:

    你假设这里的 php 从上到下执行,但它并不像那样工作:

    <?php
    foo();  # works
    
    function foo(){
      print "bar";
    }
    

    <?php
    
    foo();  #dies
    
    if( $i == 1 )
    {
      function foo(){
        print "bar";
      }
    }
    

    <?php
    $i = 1;
    if( $i == 1 )
    {
      function foo(){
        print "bar";
      }
    }
    
    foo(); #works
    

    现在,虽然您可以有条件地创建类:

    <?php
    
    class A { }
    class B { }
    if( false ){ 
      class C extends B { 
        public static function bar(){
          print "baz"; 
        }
      }
    }
    C::bar(); # dies
    

    你不能在运行时从一个变量中实例化一个:

    <?php
    class A { }
    class B { }
    $x = 'B'; 
    if( false ){ 
      class C extends $x { 
        public static function bar(){
          print "baz"; 
        }
      }
    }
    C::bar();
    ---> Parse error: syntax error, unexpected T_VARIABLE, expecting T_STRING in /tmp/eg.php on line 7
    

    有一种使用 Eval 的方法,但你真的不想去那里:

    <?php
    
    class A { }
    class B { }
    $x = 'B'; 
    if( true ){ 
     $code =<<<EOF
      class C extends $x { 
        public static function bar(){
          print "baz"; 
        }
      }
    EOF;
    
      eval( $code );
    }
    C::bar();
    $o = new C; 
    if ( $o instanceof $x )
    {
      print "WIN!\n";
    }
    --->barWIN!
    

    不过,这里还有一个更重要的问题:

    你到底为什么要想要在运行时扩展一个不同的类

    任何使用你的代码的人都会想阻止你并鞭打你。

    (或者,如果您喜欢鞭打,请使用 eval 技巧)

    【讨论】:

    • 在理想的世界里,人们不会想要这样做。但这不是一个理想的世界。我查找了这个,因为我坚持使用 Joomla 更改父类以在版本 1.5.x 和更高版本之间定义新的“元素”。我的子类不需要不同,我不想要不同的代码库,所以我希望能够根据 Joomla 的版本从不同的类继承。这就是为什么。
    • 似乎泛型无法使用 PHP,令人失望,我想用这种方式破解它!
    • @user185631 出于完全相同的原因来到这里。
    • 你为什么要在运行时扩展一个不同的类?测试,模拟一个静态方法:(
    • @Abdillah PHP 是错误的工具。将 eval 混入其中的原因为安全漏洞带来了深不可测的风险。也就是说,您仍然可以这样做,但不要自欺欺人地认为您正在做的事情以任何方式“很好”,并确保您不会试图在生产堆栈中使用该代码,只是作为预防措施.
    【解决方案2】:

    我看不出这会特别有用,但要回答您的问题……不。没有办法动态地做到这一点,因为生成的类必须在评估变量之前实例化(如果这有意义的话)。

    简单地说:类必须存在才能正确执行代码。

    【讨论】:

      【解决方案3】:

      如果您没有太多的 $blah 值,您可以在不同的文件中扩展每个值,然后 require_once "classes/foo_$blah.php"

      否则,您将无法使用 eval() 解决方案...祝您好运... :)

      【讨论】:

      【解决方案4】:

      我知道这个问题很久以前就被问过了,但是答案比较简单。

      假设如果你想要扩展类 foo 如果类 foo 存在,或者类 bar 如果它不存在,你会使用:

      if(!class_exists('foo')) {
          class foo extends bar {
              function __construct() {
                  parent::__construct();
              }
          }
      }
      
      class myclass extends foo{
          //YOUR CLASS HERE
      }
      

      【讨论】:

      • 这是一个可行的想法......如果有 5 个可能的类可以扩展,这有点难看。
      • 同意,但是从您的一个 cmets 看来,您正在为 Joomla 开发。我假设您尝试扩展的类是否可用,具体取决于 Joomla 的版本,所以我猜测可能的类将限制为两个左右。不幸的是,没有简单的方法(据我所知)使用变量代替类名,即你不能写 class myclass extends $classvar {} 所以这是最好的选择。不过你是对的...... 5+ 可能的课程会变得丑陋!
      • foo 中不需要添加 __construct。
      【解决方案5】:

      我认为这是为了便于维护,对吧?在运行时扩展一个类真的很疯狂。

      class SuperClassOne { /* code */ }
      class SuperClassTwo { /* code */ }
      
      class IntermediateClass extends SuperClassOne { /* empty! */ }
      
      class DescendantClassFoo extends IntermediateClass{ }
      class DescendantClassBar extends IntermediateClass{ }
      class DescendantClassBaz extends IntermediateClass{ }
      

      然后,当您想要更改所有 DescendantClass* 类时,您只需更改 IntermediateClass 扩展的内容:

      class IntermediateClass extends SuperClassTwo { }
      

      【讨论】:

      • 单行 cmets 使用不当。右括号 } 已注释!
      【解决方案6】:

      使用PHP overloading可以在一定程度上做到这一点。

      class variable_class {
          public $orginalBaseClass;
          public $orginalArgs;
      
          public function __construct() {
              // Get constructor parameters.
              $this->orginalArgs = func_get_args();
              // Get class name from args or 3rd party source.
              $classname = 'stdClass';
      
              // Pass along args to new class.
              $this->orginalBaseClass = new $classname($this->orginalArgs);
          }
      
          public function __call($name, $arguments) {
              // Pass all method calls to the orginalBaseClass.
              return call_user_func_array(array($this->orginalBaseClass, $name), $arguments);
          }
      }
      

      我在Drupal module 中使用此模式来表示prefetching data from the cache

      【讨论】:

        【解决方案7】:

        我用定义和吠叫测试了一些东西:

        <?php
            define("INHERIT",A);
        
            class A{
                public function bark(){
                    return "I'm A";
                }
            }
            class B{
                public function bark(){
                    return "I'm B";
                }
            }
        
            class C extends INHERIT{}
        
            //main?
            $dog = new C();
            echo $dog->bark();
        ?>
        

        输出是:

        致命错误:找不到类“INHERIT” 在 D:\sites\inherit.php 第 15 行

        所以“变量类扩展可能吗?”的答案。是:没有。

        【讨论】:

        • 但是你可以创建一个可以继承任何东西的类,方法是继承一个 MultipleInheriter 类,该类在数组中有一个类的列表,然后它在静态上下文中调用带有 __call 的方法,所以 $this 里面方法被翻译成当前类。只有 public METHODS 可以工作,所以它是一个真正的假继承。然后,您将调用 extend() 方法并将一个类添加到列表中。
        【解决方案8】:

        你应该尝试过 $$

        $blah = 'foo1';
        class foo2 extends $$blah {
            //...
        }
        
        class foo1 {
            //...
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-22
          相关资源
          最近更新 更多