亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

PHP 事件驅動框架實踐

2020-03-22 19:46:49
字體:
來源:轉載
供稿:網友
  • 關于PHP事件驅動框架的一些基本信息請先看我上一篇博客(基于CodeIgniter的事件驅動擴展和開發規范http://www.it165.net/pro/html/201206/2945.html)

    這里將使用上一篇博客中的寫的事件類和規范來寫一個簡單 用php 和 mysql 模擬文件系統的增刪改查 例子。

    步驟



    1.數據庫設計和基本結構

      1.1我們用一張表來表示文件和文件夾,主要字段和意義如下表所示。

    id 文件的唯一標識id   name 文件名 uid 文件創建者的id created 文件創建的時間戳 modified 文件修改的時間戳 size     文件大小 type     文件類型 pid   文件父目錄的id path 文件的物理位置 route 文件從父目錄到根節點的所有祖先id   version 文件版本號

        文件系統是一種簡單的樹形結構,特點是:文件夾節點有子節點,文件節點沒有子節點。

    2.類設計和定義

      2.1要考慮的問題

        從要實現的操作“增、刪、改、查”來看,要考慮的主要問題只有一個,就是在對文件夾節點進行刪改操作時,如何讓上層目錄和下層文件或文件夾進行相應的更改。

      2.2希望的寫法

        1.對文件類(也可以用來表示文件夾)有簡單的save , set , delete 等方法。

        2.希望有一個類來表示文件的所有祖先節點,這個類可以是一個簡單的文件類的集合。它在必要時可以將所有的祖先文件夾實例化。它能提供一些簡單的集合操作方法。

        3.希望有一個類來表示文件的所有子文件和子文件夾,他能提供一些方法讓我批量操作子文件或文件夾。

      2.3類定義

        這里的實體類,和實體集合類參考了前端框架backbone。

        我先定義了一個實體類,這個類有基本增刪改查操作。


    class Entity {    private $attributes = array();    private $is_deleted = false;    public function __construct() {    }    public function reset( $data ) {        $this -> chunk();        return $this -> set( $data );    }    public function get( $attr_name ) {        return isset( $this -> attributes[$attr_name] ) ? $this -> attributes[$attr_name]->value : false;    }        public function get_attr_detail( $attr_name ){        return isset( $this -> attributes[$attr_name] ) ? $this -> attributes[$attr_name] : false;    }    public function set() {        if( $this -> is_deleted ){            return false;        }                $args = func_get_args();        if( count( $args) == 1 ){            $attr_array = ( array ) $args[0];        }else if(  count( $args) == 2 ){            $attr_array = array($args[0] => $args[1] );        }        foreach( $attr_array as $key => $value ) {            $value_obj = new stdClass();            $value_obj ->  changed = false;            $value_obj ->  new = true;                        if( isset($this -> attributes[$key])){                $value_obj -> new  = false;                if( $this -> attributes[$key] -> value !== $value ){                    $value_obj -> changed  = true;                    $value_obj -> last  = $this -> attributes[$key] -> value;                }            }            $value_obj -> value = $value;                        $this -> attributes[$key] = $value_obj;        }        return $this;    }    public function chunk() {        $this -> attributes = array( );        return $this;    }    public function save() {        return false;    }        public function delete(){        $this -> deleted = true;    }        public function to_object() {        $object = new stdClass();        foreach( $this -> attributes as $key => $value_obj ) {            $object -> $key = $value_obj ->value;        }        return $object;    }    public function to_array() {        return ( array ) $this -> to_object();    }        public function is_empty(){        return empty( $this -> attributes );    }        public function is_delete(){        return $this -> deleted;    }}

        然后定義了一個集合類,這個類實現了spl的IteratorAggregate 接口,使得php可以對它進行foreach操作。


    class Entity_collection implements IteratorAggregate{    public $length = 0;    public $options = array(        'child_class' => "Entity"    );    public $children = array( );    public function __construct( $options ) {                $this -> options = array_merge( $this -> options, $options );            $this -> load_children( $this -> options );    }        private function load_children( &$options ){        if( !empty( $options['children_data'] ) ) {            $this -> reset_from_data( $options['children_data'] );                    } else if( !empty( $options['children'] ) ) {                        $this -> reset( $options['children'] );        }    }    public function to_array() {        $output = array( );        foreach( $this -> children as $child ) {            $output[] = $child -> to_object();        }        return $output;    }    public function reset( &$children ) {        $this -> children = $children;        $this -> length = count( $children );    }    public function reset_from_data( $children_data ) {        foreach( $children_data as $child_data ) {            $class_name = $this -> options['child_class'];            $children_obj = new $class_name( $child_data );            if( !$children_obj -> is_empty() ){                $this -> children[] = $children_obj;            }        }                $this -> length = count( $this -> children );    }        public function get( $id ){        foreach( $this -> children as &$child ){            if( $child -> get("id") == $id ){                return $child;            }        }        return false;    }        public function getIterator(){        return new ArrayIterator( $this -> children );    }}

      定義了文件(文件夾)類,繼承自實體類。這里注意里面使用另一個叫做file_database的單例,這個單例是用來進行具體數據庫操作。單獨提出來是為了提高擴展性。用戶可以通過修改file_database類來應對自己的需求。


    class File extends Entity{    private $file_database;    public function __construct( $fid = false ){        parent::__construct();        $this -> file_database = File_database::get_instance();        if( $fid ){            if( is_object( $fid ) || is_array( $fid ) ){                $data = $fid;            }else{                $data = $this -> file_database -> load_file( $fid );            }            $this -> reset( $data );        }    }    public function save(){        $data = $this -> to_object();        $id = $this -> get( 'id' );        if( $id ){            $new_data = $this -> file_database -> update_file( $data );        }else{            $new_data = $this -> file_database -> insert_file( $data );        }        if( $new_data ){            $this -> reset( $new_data );        }else{            //錯誤處理        }        return $this;    }        public function delete(){            }}

      文件祖先類,這里注意它不是直接集成自實體集合類。


    class File_ancenstors implements IteratorAggregate{    public $file = false;    public $ancestors;    public function __construct( $fid ){        $this -> file = new File( $fid );        $this -> load_ancestor_entities( $this -> file -> get( 'route' ) );    }    private function load_ancestor_entities( $route ){        $ancestor_ids = explode( '/', $route );        $collection_options = array(            'child_class' => "File",            'children_data' => $ancestor_ids        );        $this -> ancestors = new Entity_collection( $collection_options );        return $this;    }        public function getIterator(){        return $this -> ancestors;    }}

        子文件(不包括后代文件)集合類


    class File_children extends Entity_collection{    private $file_database;        public function __construct( $fid ){        $this -> file_database = File_database::get_instance();        $options = array(            'child_class' => 'File',        );        parent::__construct( $options );                $this -> load_children_entities( $fid );    }    public function load_children_entities( $fid ){        $children_data = $this -> file_database -> load_children_files( $fid );        $this -> reset_from_data( $children_data  );        return $this;    }}

      最后數據庫操作類


    class File_database{    const table = 'files';    static $instance = false;    private $CI = false;    static function get_instance(){        if( !File_database::$instance ){            new File_database();                    }        return File_database::$instance;    }    private $db;    public function __construct(){        $this -> CI = &get_instance();        $this -> db = $this -> CI -> db;                self::$instance = &$this;    }    public function load_file( $fid ){        $mid = $this -> CI -> user -> id % var_get("user_mod");        $table_name = self::table ."_{$mid}";        return $this -> db -> get_where( $table_name, array( "id" => $fid ) ) -> row();    }    public function update_file( $file ){        if( !isset( $file -> id ) ){            return false;        }        $update_data = ( array ) $file;        $mid = $update_data['uid'] % var_get("user_mod");        $table_name = self::table."_{$mid}";        $this -> db -> where( "id", $update_data['id'] );        unset( $update_data['id'] );        $update_result = $this -> db -> update( $table_name, $update_data );        return $update_result ? $file : false;    }    public function insert_file( $file ){        if( isset( $file -> id ) ){            return false;        }        $insert_data = ( array ) $file;        $insert_data['id'] = $this -> generate_file_id();        $mid = $insert_data['uid'] % var_get("user_mod");        $table_name = self::table."_{$mid}";        $insert_result = $this -> db -> insert( $table_name, $insert_data );        if( $insert_result ){            $this -> db -> where( 'id', $insert_data['id'] );            $new_data = $this -> db -> get( $table_name ) -> row();        }        return $insert_result ? $new_data : false;    }    private function generate_file_id(){        do{            $fid = $this -> salt( 16 );        }while( $this -> file_id_exist( $fid ) );        return $fid;    }    private function salt( $length = 16 ){        return substr( md5( uniqid( rand(), true ) ), 0, $length );    }    public function file_id_exist( $fid ){        if( $this-> db -> query( "SELECT id FROM files WHERE id = '{$fid}'" ) -> num_rows() ){            return true;        }        return false;    }        public function load_children_files( $fid ){        $mid = $this -> CI -> user -> id % var_get("user_mod");        $table_name = self::table ."_{$mid}";                $this -> db -> where( 'pid', $fid );        $mysql_result = $this -> db -> get( $table_name );        return $mysql_result ? $mysql_result -> result() : array();    }}

    3.模塊定義

      3.1希望的寫法

        1.希望在寫對任何一個節點的邏輯操作時,無論增刪改查,我都可以先只考慮考慮當前節點。通過拋出事件讓自己的模塊,或者其他擴展模塊來決定要不要進行相應的其他操作。

        2.在寫任何一個針對文件某一變化(如修改、刪除)時,代碼不關心只對自己模塊內的變化負責。

      3.2模塊實現

        這里我使用CodeIgniter作為基礎框架,讀者也可以直接自己移植。具體的內容請看注釋。


    <?php/** * @author 侯振宇 * @date 2012-6-26 * @encode UTF-8 */class File_model extends CI_Model{        public function __construct(  ){        parent::__construct( );        //file factory 包含了和文件相關的類        $this -> load -> library("File_factory");    }    //聲明本模塊需要進行權限驗證的接口    public function auth(){        return array(            'main/file_list' => array(                'file_owner_validate' => array(                    'validate' => 'is_operator_file_owner'                )            ),            'main/file_update' => array(                'file_owner_validate' => array(                    'validate' => 'is_operator_file_owner'                )            )        );    }    //聲明模塊要監聽的事件,可以是內部事件,也可以是外部事件。    //這里監聽的都是內部的文件操作的事件,如果修改,增加。為的是分離祖先后者后臺的連帶操作。    public function listen(){        return array(            "file_update" => "react_file_update",            "file_insert" => "react_file_insert",            "file_remove" => "react_file_remove",        );    }        //文件更新后   更新父目錄的size等屬性。    public function react_file_update( $file ){                //size        if( $file -> get_attr_detail("size") -> changed ){            $size_change_value = $file -> get("size") - $file -> get_attr_detail("size") -> last;            $ancestors = new File_ancenstors( $file->get("id") );            foreach( $ancestors as &$ancestor ){                $ancestor -> set( "size", $ancestor -> get("size") + $size_change_value );                $ancestor -> save();            }        }    }        //文件插入后,更新文件route。當然這個操作你可以在文件新建的時候就寫好,這里只是示例。    public function react_file_insert( $file ){        $pfile = new File( $file -> get("pid") );        $file_route = explode('/', $pfile -> get('route') );        array_push( $file_route,  $file -> get("pid") );        $file_route_str = implode('/', array_filter( $file_route) );                $file -> set("route" , $file_route_str) -> save();    }        public function is_operator_file_owner(){        //根據自己情況進行判斷        return true;    }        //文件的一個列表    public function file_list( $fid ){        $files = new File_children( $fid );        return $files -> to_array();    }        //單個文件載入    public function file_load($fid){        $file = new File( $fid );        return $file -> to_object();    }        //某一文件的祖先    public function file_ancestors( $fid ){        $file_ancenstors = new File_ancenstors( $fid );        return  $file_ancenstors -> ancestors -> to_array()  ;    }        //創建文件    public function file_new(){        //測試例子        $file_attrs = array(            'name' =>  "new_test",            'uid' => 151,            'created' => now(),            'pid' => '8a0341838c007cf4',        );                $file = new File( $file_attrs );        $file -> save();        $this -> event -> trigger("file_insert", $file );        return $file;            }        //創建文件夾    public function folder_new( $pid, $name ){        $file_attrs = array(            'name' =>  $name,            'uid' => $this -> user -> id,            'created' => now(),            'pid' => $pid,        );                $file = new File( $file_attrs );        $file -> save();        $this -> event -> trigger("file_insert", $file );        return  $file -> to_object() ;    }                //文件更新    public function file_update( $fid, $data ){        $file = new File( $fid );        $file -> set( $data );        $file -> save();        $this -> event -> trigger( "file_update", $file );    }}?>

    總結


    事件驅動 相比模塊間通過接口來溝通的最大好處應該是進一步降低了耦合,同時使系統的邏輯更容易閱讀。

    希望讀者能夠仔細閱讀代碼,能給我提出一些您的寶貴建議。畢竟我不希望我的博客只是放出一個現成的東西,編程讓大家測試一下而已。貴在交流。

    我有兩個項目會基于事件驅動來做,非商業的,開源的,個人覺得還比較好玩。有興趣參與的請與我聯系。留言或者email都可以。謝謝。

    PHP編程

    鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

  • 發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
    91精品久久久久久久久久久久久| 91九色单男在线观看| 91网站免费看| 精品一区电影国产| 亚洲成年人影院在线| 精品国产一区二区三区久久久| 亚洲精品日产aⅴ| 欧美性猛交xxxxx水多| 色悠悠国产精品| 少妇高潮 亚洲精品| 欧美一级淫片videoshd| 国产一区av在线| 亚洲伊人一本大道中文字幕| 久久五月情影视| 69国产精品成人在线播放| 欧美精品18videos性欧美| 色噜噜狠狠狠综合曰曰曰88av| 亚洲精品福利免费在线观看| 超碰日本道色综合久久综合| 亚洲美女又黄又爽在线观看| 亚洲国产小视频| 久久久av亚洲男天堂| 成人福利网站在线观看| 精品国产福利在线| 亚洲国产欧美自拍| 7m第一福利500精品视频| 国产精品成人aaaaa网站| 亚洲影院色在线观看免费| 日韩国产精品亚洲а∨天堂免| 日韩欧美国产骚| 亚洲国产日韩欧美综合久久| 亲爱的老师9免费观看全集电视剧| 日韩av手机在线观看| 日韩在线观看免费高清完整版| 97免费在线视频| 97精品一区二区三区| 2019中文字幕在线| 欧美精品激情在线观看| 日韩av在线不卡| 秋霞av国产精品一区| 亚洲综合日韩中文字幕v在线| 7777精品久久久久久| 国产精品久久久久久久久久久不卡| 日韩成人免费视频| 中文字幕九色91在线| 国产精品久久久久久久美男| 在线视频日韩精品| 欧美黑人巨大xxx极品| 欧美在线视频一二三| 久久偷看各类女兵18女厕嘘嘘| 国产精品露脸自拍| 久久久亚洲影院你懂的| 国产一区二区三区丝袜| 日韩中文字幕视频在线观看| 精品国产老师黑色丝袜高跟鞋| 91精品视频观看| 亚洲资源在线看| 日韩专区在线观看| 欧美尤物巨大精品爽| 精品国产一区二区三区久久狼5月| 7m精品福利视频导航| 久久久久久久久91| 国产精品香蕉av| 91超碰caoporn97人人| 亚洲自拍偷拍区| 精品亚洲va在线va天堂资源站| 日韩电视剧在线观看免费网站| 国产欧美日韩综合精品| 国产美女扒开尿口久久久| 成人性教育视频在线观看| 欧美日韩一区二区三区| 国产精品成av人在线视午夜片| 日韩影视在线观看| 视频在线一区二区| 中文字幕一精品亚洲无线一区| 亚洲视频精品在线| 久久精品99久久久香蕉| 国产精品成久久久久三级| 国产免费成人av| 国产视频精品va久久久久久| 精品国内亚洲在观看18黄| 欧美日韩国产成人高清视频| 亚洲成人教育av| 亚洲人成网站在线播| 96pao国产成视频永久免费| 91在线视频精品| 中文字幕在线看视频国产欧美| 97香蕉久久超级碰碰高清版| 2018中文字幕一区二区三区| 精品国产乱码久久久久久天美| 成人午夜一级二级三级| 中文字幕一区二区三区电影| 欧美中文字幕在线| 中文字幕视频在线免费欧美日韩综合在线看| 欧美第一页在线| 欧美视频国产精品| www.亚洲男人天堂| 日韩免费av一区二区| 另类天堂视频在线观看| 久久亚洲一区二区三区四区五区高| 亚洲free嫩bbb| 欧美在线一区二区三区四| 92看片淫黄大片欧美看国产片| 777国产偷窥盗摄精品视频| 欧美在线一区二区视频| 91久久精品美女高潮| 国产精品午夜视频| 亚洲一区二区自拍| 国产视频久久网| www.亚洲天堂| 欧美体内谢she精2性欧美| 国产日韩欧美在线| 韩剧1988在线观看免费完整版| 国产原创欧美精品| 精品久久中文字幕| 久久久女人电视剧免费播放下载| 欧美色欧美亚洲高清在线视频| 国产欧美中文字幕| 亚洲激情国产精品| 精品国产视频在线| 中文字幕日韩欧美精品在线观看| 中日韩美女免费视频网址在线观看| 欧美精品电影在线| 久久精品99久久久香蕉| 久久精品视频va| 亚洲丝袜一区在线| 成人免费观看a| 欧美视频在线观看免费| 欧美在线一区二区三区四| 欧美日韩国产精品专区| 久久亚洲综合国产精品99麻豆精品福利| 91av在线视频观看| 亚洲国产成人爱av在线播放| 欧美成人精品一区二区| 国产精品亚洲综合天堂夜夜| 国产精品久久久久99| www国产亚洲精品久久网站| www欧美xxxx| 国产精品高潮呻吟久久av无限| 色噜噜狠狠狠综合曰曰曰| 亚洲欧美在线第一页| 韩国欧美亚洲国产| 欧美精品日韩三级| 国产亚洲精品成人av久久ww| 欧美天天综合色影久久精品| 亚洲视频axxx| 亚洲mm色国产网站| 亚洲精品suv精品一区二区| 亚洲欧美日韩国产中文专区| 亚洲淫片在线视频| 亚洲区bt下载| 亚洲欧美日韩精品久久奇米色影视| 高清亚洲成在人网站天堂| 国产精品99久久久久久人| 少妇高潮 亚洲精品| 日韩欧美成人免费视频| 高清在线视频日韩欧美| 久99九色视频在线观看| 丝袜一区二区三区| 清纯唯美日韩制服另类| 欧美电影免费在线观看| 国产欧美日韩丝袜精品一区| 米奇精品一区二区三区在线观看| 日韩精品中文字幕在线播放|