PHP中的变量变量类扩展--可能吗?

Variable variable class extensions in PHP--is it possible?

提问人:Darryl Hein 提问时间:11/20/2008 最后编辑:Darryl Hein 更新时间:8/10/2017 访问量:7940

问:

在PHP中可以做到以下情况吗?

$blah = 'foo1';

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

class foo1 {
    //...
}

这给出了一个错误。

我想动态设置$blah以便我可以扩展我想要的任何类。

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

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

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

PHP 对象 变量

评论


答:

2赞 Jeff Hubbard 11/20/2008 #1

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

简单地说:在代码可以正确执行之前,类必须存在。

16赞 Kent Fredric 11/20/2008 #2

你在这里假设 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 技巧)

评论

2赞 user185631 7/27/2012
在一个理想的世界里,人们不会想这样做。但这不是一个理想的世界。我查了一下,因为我坚持使用 Joomla 更改父类以在 1.5.x 版和更高版本之间定义新的“元素”。我的子类不需要不同,我不想要不同的代码库,所以我希望能够根据 Joomla 的版本从不同的类继承。这就是原因。
0赞 Ziyan Junaideen 5/5/2013
PHP似乎无法使用泛型,令人失望,我想用这种方式破解它!
0赞 mavrosxristoforos 10/16/2013
@user185631 出于同样的原因来到这里。
0赞 Abdillah 6/27/2018
你到底为什么要在运行时扩展一个不同的类?测试、模拟静态方法:(
0赞 Kent Fredric 5/16/2019
@Abdillah PHP是那里的工作的错误工具。将 eval 投入其中的原因为安全漏洞提供了深不可测的风险。也就是说,你仍然可以这样做,但不要自欺欺人地认为你正在做的事情在任何方面都是“好的”,并确保你不会试图在你的生产堆栈中使用该代码,只是为了以防万一。
2赞 nickf 11/20/2008 #3

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

class SuperClassOne { /* code */ }
class SuperClassTwo { /* code */ }

class IntermediateClass extends SuperClassOne { /* empty! */ }

class DescendantClassFoo extends IntermediateClass{ }
class DescendantClassBar extends IntermediateClass{ }
class DescendantClassBaz extends IntermediateClass{ }

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

class IntermediateClass extends SuperClassTwo { }

评论

1赞 luiscubal 12/4/2009
单行注释使用不当。右括号 } 被注释!
2赞 Greg 11/20/2008 #4

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

否则,你就会被解决方案困住......祝你好运... :)eval()

评论

0赞 Franz Holzinger 2/20/2020
这是行不通的。查看 stackoverflow.com/questions/23726288/...
-2赞 Matthew 11/2/2009 #5

你应该试过 $$

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

class foo1 {
    //...
}
1赞 SparK 5/27/2011 #6

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

<?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” 在第 15 行的 D:\sites\inherit.php 中

因此,“变量类扩展可能吗?”的答案是:不。

评论

0赞 SparK 11/4/2011
但是,您可以通过继承一个 MultipleInheriter 类来创建一个可以从任何内容继承的类,该类在数组中具有类列表,然后在静态上下文中调用具有 __call 的方法,以便将方法中的$this转换为当前类。只有公共方法才能起作用,所以这是一个非常假的继承。然后,您将调用 extend() 方法并将一个类添加到列表中。
4赞 whizzkid 10/1/2012 #7

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

假设如果类 foo 存在,则要扩展类 foo,如果不存在,则要扩展类栏,则使用:

if(!class_exists('foo')) {
    class foo extends bar {
        function __construct() {
            parent::__construct();
        }
    }
}

class myclass extends foo{
    //YOUR CLASS HERE
}

评论

0赞 Darryl Hein 10/4/2012
这是一个可能可行的想法......如果有 5 个可能的类,您可能想要扩展,那就有点丑陋了。
0赞 whizzkid 10/5/2012
同意,但从您的一条评论来看,您似乎正在为 Joomla 开发。我假设您尝试扩展的类可用或不可用,具体取决于 Joomla 的版本,所以我猜可能的类将限制为两个左右。不幸的是,没有简单的方法(据我所知)使用变量代替类名,即您不能将类 myclass 扩展$classvar {},所以这是最好的选择。不过你是对的......5+ 可能的课程会变得丑陋!
0赞 Kjeld 6/16/2018
无需向 foo 添加__construct。
3赞 mikeytown2 1/28/2015 #8

使用PHP重载可以在一定程度上实现这一点。

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 模块中使用这种模式从缓存中预取数据