2009-07-29 59 views
27

这是我想做的事:在运行时在php中动态生成类?

$clsName = substr(md5(rand()),0,10); //generate a random name 
$cls = new $clsName(); //create a new instance 

function __autoload($class_name) 
{ 
    //define that instance dynamically 
} 

显然,这不是什么我实际上做,但基本上我有一类未知的名称和基于名称,我想生成带班某些属性等

我使用eval()尝试,但它给我套在私人和$这个 - >引用...

//编辑

好吧,显然我的短,甜蜜的“这就是我想要做的”造成的巨大在那些能够提供答案的人中间发生冲突和惊慌。为了得到实际的答案,我会更详细。

我有一个验证框架使用我维护的网站上的代码提示。每个函数有两个定义

function DoSomething($param, $param2){ 
    //code 
} 
function DoSomething_Validate(vInteger $param, vFloat $param2){ 
    //return what to do if validation fails 
} 

我正在为我的数据库中的主键添加验证程序。我不想为每个表格创建一个单独的类(203)。所以我的计划是这样做

function DoSomething_Validate(vPrimaryKey_Products $id){ } 

凡__autoload会产生vPrimaryKey的子类,设置表格参数产品。

现在快乐吗?

+1

我建议你告诉我们你到底想要做什么,并问我们如何做得更好。你所尝试的不是正确的做法。 – hobodave 2009-07-29 23:30:46

+2

我提高了这一点,所以没有反对票。这是一个有效的问题,即使这是一个坏主意。 – MitMaro 2009-07-29 23:38:05

+0

我已更新问题。 – 2009-07-29 23:49:40

回答

4

这几乎肯定是一个坏主意。

我想你的时间会更好用于创建一个脚本,它可以为你创建你的类定义,而不是在运行时尝试这样做。

东西用命令行标志,如:

./generate_classes_from_db <host> <database> [tables] [output dir] 
2

使用eval()真的是一个坏主意。它打开了一个大的安全漏洞。只是不要使用它!

2

请阅读其他人的回答,以了解这如何是一个非常糟糕的主意。

一旦你明白了,这里是一个小的演示,你可以怎么做,但不应该这样做。


<?php 
$clname = "TestClass"; 

eval("class $clname{}; \$cls = new $clname();"); 

var_dump($cls); 
13

其滑稽,其实这是为数不多的东西的地方EVAL似乎没有这样一个坏主意一个。

只要你能确保没有用户输入将会进入eval。

当你使用字节码缓存代码不会被缓存等等时,你仍然有缺点,但是eval的安全问题与在eval中有用户输入或者在错误的范围内结束很相关。

如果你知道你在做什么,eval会帮助你做到这一点。

这就是说,在我看来,你好得多,当你没有依赖型,提示您验证,但你有一个功能

DoSomething_Validate($id) 
{ 
    // get_class($id) and other validation foo here 
} 
3
function __autoload($class) { 
    $code = "class $class {` 
     public function run() { 
      echo '$class<br>'; 
     } 
     ".' 
     public function __call($name,$args) { 
      $args=implode(",",$args); 
      echo "$name ($args)<br>"; 
     } 
    }'; 

    eval($code); 
} 

$app=new Klasse(); 
$app->run(); 
$app->HelloWorld(); 

这可能有助于在创建一个类运行。 它还为未知方法创建方法运行和方法 但是在运行时更好地创建对象,而不是类。

10

我知道这是一个老问题,有答案可行,但我想提供一些片段来回答原来的问题,我想提供一个更加扩展的解决方案,如果有人最终在这里像我一样寻找这个问题的答案。

创建一个动态类

<?php 
// Without properties 
$myclassname = "anewclassname"; 
eval("class {$myclassname} { }"; 
// With a property 
$myclassname = "anewclassname"; 
$myproperty = "newproperty"; 
eval("class {$myclassname} { protected \${$myproperty}; }"; 
?> 

只要你正确地逃脱你的文字,你也可以在里面添加一个功能。

但是如果你想动态地创建基于本身是动态的东西的类,比如为数据库中的每个表创建一个类,就像提到的原始问题那样呢?

创建多个动态类

<?php 

// Assumes $dbh is a pdo connection handle to your MySQL database 
$stmt=$dbh->prepare("show tables"); 
$stmt->execute(); 
$result = $stmt->fetchAll(PDO::FETCH_ASSOC); 
$handle = null; 
$classcode = ''; 
foreach ($result as $key => $value) { 
    foreach ($value as $key => $value) { 
     $classcode = "class {$value} { "; 
     $stmt2=$dbh->prepare("DESC $value"); 
     $stmt2->execute(); 
     $result2 = $stmt2->fetchAll(PDO::FETCH_ASSOC); 
     foreach ($result2 as $key => $value) { 
      $classcode .= "public \${$value['Field']}; "; 
     } 
     $classcode .= "}"; 
     eval($classcode); 
    } 
} 

?> 

这将动态生成一个数据库中的每个表中的一类。对于每个类,在每个列之后命名的属性也将被创建。

现在有人指出你不应该这样做。只要您控制评估中发生的事情,安全风险就不成问题。但是 - 如果您对此深思熟虑,最有可能的解决方案更有意义。我认为我有完美的用例来动态创建新类。仔细检查问题证明不然。

一个潜在的解决方案 - 使用stdClass创建只是数据容器的对象,不需要任何方法。

另外 - 如上所述,你可以使用脚本手动生成大量的类。在类镜像数据库表的情况下,您可以使用与上面相同的逻辑,而不是进行评估,将该信息写入文件。

4

我认为使用eval()这不是一个可靠的解决方案,特别是如果您的脚本或软件将分发给不同的客户端。共享主机提供商始终禁用eval()功能。

我想一个更好的形式给出的是这样的:

<?php 

function __autoload($class) { 
     require 'classes/'.$class.'.php'; 

} 

$class = 'App'; 
$code = "<?php class $class { 
    public function run() { 
     echo '$class<br>'; 
    } 
    ".' 
    public function __call($name,$args) { 
     $args=implode(",",$args); 
     echo "$name ($args)<br>"; 
    } 
}'; 

file_put_contents('classes/App.php' ,$code); 

$a = new $class(); 
$a->run(); 

完成执行的代码后,你可以删除该文件,如果你愿意,我测试了它和它完美的作品。