摘要:作者上一篇提到了類的自動加載和,今天就來逐一說說。為這個問題提供了一個解決方案,這就是類的自動裝載機制。為了方便使用自定義的全局,把方法也重寫了。
作者:Terry Gao
上一篇提到了類的自動加載和Session,今天就來逐一說說。
1. 類的自動加載在使用PHP的OO模式開發系統時,通常大家習慣將每個類的實現都存放在一個多帶帶的文件里,這樣會很容易實現對類進行復用,同時將來維護時也很便利,這也是OO設計的基本思想之一。如果需要使用一個類,只需要直接使用include/require將其包含進來即可。但隨著項目規模的不斷擴大,使用這種方式會帶來一些隱含的問題:如果一個PHP文件需要使用很多其它類,那么就需要很多的require/include語句,這樣有可能會造成遺漏或者包含進不必要的類文件。如果大量的文件都需要使用其它的類,那么要保證每個文件都包含正確的類文件肯定是一個噩夢。
PHP5為這個問題提供了一個解決方案,這就是類的自動裝載(autoload)機制。
/* NovaFrameworkAutoloader.php */ import()注冊到sql_autoload,作為本項目中類的自動加載方法 spl_autoload_register(array( $this, "import" )); } /** * Autoloader的入口函數 * 用于創建Autoloader的唯一實例化對象 * * @return Autoloader */ public static function init() { if (self::$loader == NULL) self::$loader = new self(); return self::$loader; } /** * 類的自動加載方法 * 根據傳入參數$className,自動引入相應類的源文件 * * @param string $className */ public function import($className) { $path = explode("", substr($className, strlen("Nova"))); $filePath = ROOT_DIR . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $path) . ".php"; if (is_file($filePath)) { require $filePath; } } }
這個自動加載類比較簡單,初始化后,只有一個主要的方法import(),它通過解析傳入進來的類名(由于我們使用了命名空間,所以類名基本上都是“NovaFrameworkAutoloader這樣的形式”),從項目根目錄開始,按照類名本身指定的路徑來定位相應類的源碼文件,如果存在該文件,則將其引入。
2. Session更多關于自動加載類的機制和原理,可以參考PHP autoload原理
默認情況下,PHP是將session以文件的形式存在服務器上,具體可以在php.ini中配置。但是實際生產環境中,稍大些的站點都不會采用這種形式,一般都會借助sql數據庫、或者nosql類型的如memcached、redis等緩存服務器來存儲session,這樣做可以有效緩解PHP服務器的壓力和處理速度,提高并發能力。
在Nova中我們使用redis服務器來存取Session。
/* NovaFrameworkSession.php get(self::$sessionId, SESSION_TABLE_NAME); if ($sessionValue) { $_SESSION = $sessionValue; } return true; } /** * 將Session變量的內容寫入Redis中 * * @return bool */ public static function write() { if (!empty($_SESSION)) { self::$redisCache->set(self::$sessionId, $_SESSION, SESSION_TABLE_NAME, SESSION_TIMEOUT); } return true; } /** * 通過刪除Redis中SessionId對應的數據來注銷Session * session_destory()是自動調用 * * @return bool */ public static function destory() { if (self::$redisCache->exists(self::$sessionId, SESSION_TABLE_NAME)) { self::$redisCache->delete(self::$sessionId, SESSION_TABLE_NAME); } setcookie(SESSION_NAME, self::$sessionId, 1, COOKIE_PATH, COOKIE_DOMAIN, FALSE); return true; } public static function close() { return true; } public static function gc() { return true; } /** * 返回一個SessionId * 若Cookie中已存在SessionId,則直接返回該SessionId * 若不存在,則按照規則新生成一個SessionId * * @return string Session Id */ public static function get_sid() { self::$userIp = Tools::real_ip(); $arr = $_COOKIE; //判斷Cookie中是否已經存在SessionId if (is_null(self::$sessionId) && empty($arr[SESSION_NAME])) { //使用MD5對用戶IP+隨機字符串加密后作為新的SessionId self::$sessionId = function_exists("com_create_guid") ? md5(self::$userIp . com_create_guid()) : md5(self::$userIp . uniqid(mt_rand(), true)); //對新的SessionId再做一次crc32運算,作為最終的SessionId self::$sessionId .= sprintf("%08x", crc32(self::$sessionId)); //將SessionId寫入Cookie中 setcookie(SESSION_NAME, self::$sessionId, time() + SESSION_TIMEOUT, COOKIE_PATH, COOKIE_DOMAIN, FALSE); $_COOKIE[SESSION_NAME] = self::$sessionId; } else { self::$sessionId = $arr[SESSION_NAME]; } //返回SessionId return self::$sessionId; } }
Nova基本上重寫了Session的一些核心處理函數。為了方便使用自定義的全局Redis Rootkey,Nova把Redis方法也重寫了。
_redis = new Redis(); $this->_redis->connect(REDIS_HOST, REDIS_PORT); } public static function get_instance($redisKey = REDIS_ROOT) { if (!(self::$_instanceObj[$redisKey] instanceof self)) { self::$_instanceObj[$redisKey] = new self; } self::$_instanceObj[$redisKey]->redisKey = $redisKey; return self::$_instanceObj[$redisKey]; } public function set_group($groupName = "") { if (empty($groupName)) { return FLASE; } $this->groupName = $groupName; $this->groupPath = implode(":", explode("/", $groupName)) . ":"; return TRUE; } public function set($key, $data, $groupName = "", $timeout = SESSION_TIMEOUT) { if (empty($groupName)) { $groupName = $this->groupName . $this->tempName; } else { $groupName = $this->groupName . $groupName; } if (is_array($data)) { $data = json_encode($data); } $redisKey = $groupName . $key; return $this->_redis->setex($redisKey, $timeout, $data); } public function get($key, $groupName = "") { if (empty($groupName)) { $groupName = $this->groupName . $this->tempName; } else { $groupName = $this->groupName . $groupName; } $redisKey = $groupName . $key; $return = ""; $temp = $this->_redis->get($redisKey); $return = json_decode($temp, 1); return empty($return) ? $temp : $return; } public function delete($key, $groupName = "") { if (empty($groupName)) { $groupName = $this->groupName . $this->tempName; } else { $groupName = $this->groupName . $groupName; } $redisKey = $groupName . $key; return $this->_redis->delete($redisKey); } public function exists($key, $groupName = "") { if (empty($groupName)) { $groupName = $this->groupName . $this->tempName; } else { $groupName = $this->groupName . $groupName; } $redisKey = $groupName . $key; return $this->_redis->exists($redisKey); } }
你可以在Github上查看Nova項目的源代碼。
如果你有任何問題或建議,可以掃描下方二維碼或者微信搜索[phpjiagoushier],關注我的微信公眾號[PHP架構],與我交流互動。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/22554.html
摘要:作者作為的入門進階,自己動手寫一個框架可以從各方面鞏固和加深你對的理解,還能了解一些架構方面的基礎知識。它將程序劃分為三層。最上面的一層,是直接面向最終用戶的視圖層。最底下的一層,是核心的模型層,負責檢索組織和處理程序所需的數據或信息。 作者:Terry Gao 作為PHP Coder的入門進階,自己動手寫一個MVC框架可以從各方面鞏固和加深你對PHP的理解,還能了解一些架構方面的基礎...
摘要:假設我們站點的域名是,用戶請求地址。模型層我們可以將數據組織和處理邏輯放在模型層,這里封裝了數據庫操作,甚至有些大型的框架會在這一層對這個數據庫進行對象化,目的都是為了組織和處理數據,然后將處理好的數據返回給控制器層。 作者:Terry Gao 1. 控制器 第一篇我們聊到路由分發會把用戶請求按照規則分發到控制器層的不同類,而默認的規則中,請求會下發到控制器的index類的main方法...
摘要:服務器通過協議與客戶端通信,因此也被稱為服務器。本文標題為從零開始搭建論壇一服務器與框架本文鏈接為更多閱讀自己動手開發網絡服務器一自己動手開發網絡服務器二自己動手開發網絡服務器三服務器網關接口實現原理分析最佳實踐指南應用淺談框架編程簡介 之前用 Django 做過一個小的站點,感覺Django太過笨重,于是就準備換一個比較輕量級的 Web 框架來玩玩。Web.py 作者已經掛掉,項目好...
摘要:因為工作中一直在使用,也一直以來想總結一下自己關于的一些知識經驗。于是把一些想法慢慢整理書寫下來,做成一本開源免費專業簡單的入門級別的小書,提供給社區。本書的后續可能會做成視頻版本,敬請期待。本作品采用署名禁止演繹國際許可協議進行許可 React.js 小書 本文作者:胡子大哈本文原文:React.js 小書 轉載請注明出處,保留原文鏈接以及作者信息 在線閱讀:http://huzi...
閱讀 2509·2023-04-25 17:37
閱讀 1189·2021-11-24 10:29
閱讀 3696·2021-09-09 11:57
閱讀 692·2021-08-10 09:41
閱讀 2243·2019-08-30 15:55
閱讀 2811·2019-08-30 15:54
閱讀 1942·2019-08-30 15:53
閱讀 895·2019-08-30 15:43