Php eval()和spl_autoload_register/_autoload()是否是在运行时创建类的唯一方法?

Php eval()和spl_autoload_register/_autoload()是否是在运行时创建类的唯一方法?,php,drupal-7,Php,Drupal 7,我正在写一个devel模块(所以请不要写“你不应该这么做”的评论) 我的框架已经使用了uu autoload(),因此我无法使用它。我想避免使用eval()和编写临时文件。有没有办法让孩子们在飞行中学习 比如,我可以使用uu call()创建方法,使用uu get()/uu set()创建属性,但我更喜欢动态创建子类。例如,在使用“用户”表时,将TableUsers作为表的子类,以确保类中的属性与表中的字段匹配。对于此实现,我将从目标用法开始: include "table.creator:/

我正在写一个devel模块(所以请不要写“你不应该这么做”的评论)

我的框架已经使用了uu autoload(),因此我无法使用它。我想避免使用eval()和编写临时文件。有没有办法让孩子们在飞行中学习


比如,我可以使用uu call()创建方法,使用uu get()/uu set()创建属性,但我更喜欢动态创建子类。例如,在使用“用户”表时,将TableUsers作为表的子类,以确保类中的属性与表中的字段匹配。

对于此实现,我将从目标用法开始:

 include "table.creator:///user_table/TableUsers/id";
 $ut = new TableUsers();
注意这应该决不能用于生产代码,但对原型设计很有用

首先定义流包装器:

class TableMaker_StreamWrapper {

    protected $_pos = 0;
    protected $_data;
    protected $_stat;

    /**
     * Opens the script file and converts markup.
     */
    public function stream_open($path, $mode, $options, &$opened_path)
    {
        // break path into table name, class name and primary key
        $parts = parse_url($path);
        $dir = $parts["path"];
        list($garbage, $tableName, $className, $primaryKey) = explode("/", $dir, 4);


        $this->_data = '<?php class '.$className.' extends MyBaseClass {'.
        '  protected $primaryKey = "'.$primaryKey.'";'.
        '}';
        return true;
    }


    public function url_stat()
    {
        return $this->_stat;
    }

    public function stream_read($count)
    {
        $ret = substr($this->_data, $this->_pos, $count);
        $this->_pos += strlen($ret);
        return $ret;
    }


    public function stream_tell()
    {
        return $this->_pos;
    }


    public function stream_eof()
    {
        return $this->_pos >= strlen($this->_data);
    }


    public function stream_stat()
    {
        return $this->_stat;
    }


    public function stream_seek($offset, $whence)
    {
        switch ($whence) {
            case SEEK_SET:
                if ($offset < strlen($this->_data) && $offset >= 0) {
                $this->_pos = $offset;
                    return true;
                } else {
                    return false;
                }
                break;

            case SEEK_CUR:
                if ($offset >= 0) {
                    $this->_pos += $offset;
                    return true;
                } else {
                    return false;
                }
                break;

            case SEEK_END:
                if (strlen($this->_data) + $offset >= 0) {
                    $this->_pos = strlen($this->_data) + $offset;
                    return true;
                } else {
                    return false;
                }
                break;

            default:
                return false;
        }
    }
}
然后,当您想要围绕一个类创建一个表包装器时,您必须

include("table.creator:///my_table/MyTableClass/id");
然后你就可以随心所欲地创建新的MyTableClass了

如果您需要额外的语法糖,您可以创建一个像这样的小工厂函数

function get_table($tableName, $className, $pk= "id"){
     if (!class_exists($className)){
          require("table.creator":///".$tableName."/".$className."/".$pk);
     }
     return new $className();
} 
那你就说吧

$table = get_table("users", "UserTable");

希望这有帮助

您确定这是正确的解决方案吗?闻起来像是XY问题。如果您所说的是在运行时使用功能对现有对象实例进行monkey修补,那么我很幸运地创建了一个流包装器,它会在include上返回一个闭包。@DamienPirsy我不确定XY问题是什么。我所希望的就是能够根据需要动态生成类,然后将实际需要的类转储到文件中以备将来调整。@Orangepill我稍微更新了我问题的结尾。Stream wrapper使您可以说
include'表。creator://tablenaem/tableclassname';并获取类定义,就像它存在于真实文件中一样:)
$table = get_table("users", "UserTable");