红酒泡绿茶 2013-05-27 06:54
浏览 32

eval()和spl_autoload_register / __autoload()只能在运行时创建类吗?

I'm writing a devel module (so please no "you shouldn't do it" comments).

My framework already uses __autoload(), so I cannot use it. I would like to refrain from using eval() and writing temporary files, too. Is there any way to creaet child classes on the fly?

Like, I can create methods using __call() and properties using __get() / __set(), but I would really prefer to dynamically create a subclass. Like, TableUsers as a subclass of Table when working with 'users' table, to make sure properties in class match fields in table.

  • 写回答

1条回答 默认 最新

  • dongyi6845 2013-05-27 07:45
    关注

    For this implementation I will start out with a targeted usage:

     include "table.creator:///user_table/TableUsers/id";
     $ut = new TableUsers();
    

    NOTE This should NEVER be used for production code but it is useful for prototyping.

    First off define a stream wrapper:

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

    Then within our code we have to register the stream wrapper like so.

    stream_register_wrapper("table.creator", "TableMaker_StreamWrapper");
    

    Then when you want to create a table wrapper around a class you have but to ...

    include("table.creator:///my_table/MyTableClass/id");
    

    and then you will be able to make new MyTableClass to your hearts content.

    if you want additional syntactic sugar you can create a little factory function like this.

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

    Then you can just say.

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

    Hope this helps

    评论

报告相同问题?

悬赏问题

  • ¥15 wpf界面一直接收PLC给过来的信号,导致UI界面操作起来会卡顿
  • ¥15 init i2c:2 freq:100000[MAIXPY]: find ov2640[MAIXPY]: find ov sensor是main文件哪里有问题吗
  • ¥15 运动想象脑电信号数据集.vhdr
  • ¥15 三因素重复测量数据R语句编写,不存在交互作用
  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒