当前位置:Gxlcms > PHP教程 > 超简洁PHPMVC

超简洁PHPMVC

时间:2021-07-01 10:21:17 帮助过:19人阅读

原生PHP语法来渲染页面,同时提供了widget功能
  1. /**
  2. * 获取和设置配置参数 支持批量定义
  3. * 如果$key是关联型数组,则会按K-V的形式写入配置
  4. * 如果$key是数字索引数组,则返回对应的配置数组
  5. * @param string|array $key 配置变量
  6. * @param array|null $value 配置值
  7. * @return array|null
  8. */
  9. function C($key,$value=null){
  10. static $_config = array();
  11. $args = func_num_args();
  12. if($args == 1){
  13. if(is_string($key)){ //如果传入的key是字符串
  14. return isset($_config[$key])?$_config[$key]:null;
  15. }
  16. if(is_array($key)){
  17. if(array_keys($key) !== range(0, count($key) - 1)){ //如果传入的key是关联数组
  18. $_config = array_merge($_config, $key);
  19. }else{
  20. $ret = array();
  21. foreach ($key as $k) {
  22. $ret[$k] = isset($_config[$k])?$_config[$k]:null;
  23. }
  24. return $ret;
  25. }
  26. }
  27. }else{
  28. if(is_string($key)){
  29. $_config[$key] = $value;
  30. }else{
  31. halt('传入参数不正确');
  32. }
  33. }
  34. return null;
  35. }
  36. /**
  37. * 调用Widget
  38. * @param string $name widget名
  39. * @param array $data 传递给widget的变量列表,key为变量名,value为变量值
  40. * @return void
  41. */
  42. function W($name, $data = array()){
  43. $fullName = $name.'Widget';
  44. if(!class_exists($fullName)){
  45. halt('Widget '.$name.'不存在');
  46. }
  47. $widget = new $fullName();
  48. $widget->invoke($data);
  49. }
  50. /**
  51. * 终止程序运行
  52. * @param string $str 终止原因
  53. * @param bool $display 是否显示调用栈,默认不显示
  54. * @return void
  55. */
  56. function halt($str, $display=false){
  57. Log::fatal($str.' debug_backtrace:'.var_export(debug_backtrace(), true));
  58. header("Content-Type:text/html; charset=utf-8");
  59. if($display){
  60. echo "
    ";
  61. debug_print_backtrace();
  62. echo "
  63. ";
  64. }
  65. echo $str;
  66. exit;
  67. }
  68. /**
  69. * 获取数据库实例
  70. * @return DB
  71. */
  72. function M(){
  73. $dbConf = C(array('DB_HOST','DB_PORT','DB_USER','DB_PWD','DB_NAME','DB_CHARSET'));
  74. return DB::getInstance($dbConf);
  75. }
  76. /**
  77. * 如果文件存在就include进来
  78. * @param string $path 文件路径
  79. * @return void
  80. */
  81. function includeIfExist($path){
  82. if(file_exists($path)){
  83. include $path;
  84. }
  85. }
  86. /**
  87. * 总控类
  88. */
  89. class SinglePHP {
  90. /**
  91. * 控制器
  92. * @var string
  93. */
  94. private $c;
  95. /**
  96. * Action
  97. * @var string
  98. */
  99. private $a;
  100. /**
  101. * 单例
  102. * @var SinglePHP
  103. */
  104. private static $_instance;
  105. /**
  106. * 构造函数,初始化配置
  107. * @param array $conf
  108. */
  109. private function __construct($conf){
  110. C($conf);
  111. }
  112. private function __clone(){}
  113. /**
  114. * 获取单例
  115. * @param array $conf
  116. * @return SinglePHP
  117. */
  118. public static function getInstance($conf){
  119. if(!(self::$_instance instanceof self)){
  120. self::$_instance = new self($conf);
  121. }
  122. return self::$_instance;
  123. }
  124. /**
  125. * 运行应用实例
  126. * @access public
  127. * @return void
  128. */
  129. public function run(){
  130. if(C('USE_SESSION') == true){
  131. session_start();
  132. }
  133. C('APP_FULL_PATH', getcwd().'/'.C('APP_PATH').'/');
  134. includeIfExist( C('APP_FULL_PATH').'/common.php');
  135. $pathMod = C('PATH_MOD');
  136. $pathMod = empty($pathMod)?'NORMAL':$pathMod;
  137. spl_autoload_register(array('SinglePHP', 'autoload'));
  138. if(strcmp(strtoupper($pathMod),'NORMAL') === 0 || !isset($_SERVER['PATH_INFO'])){
  139. $this->c = isset($_GET['c'])?$_GET['c']:'Index';
  140. $this->a = isset($_GET['a'])?$_GET['a']:'Index';
  141. }else{
  142. $pathInfo = isset($_SERVER['PATH_INFO'])?$_SERVER['PATH_INFO']:'';
  143. $pathInfoArr = explode('/',trim($pathInfo,'/'));
  144. if(isset($pathInfoArr[0]) && $pathInfoArr[0] !== ''){
  145. $this->c = $pathInfoArr[0];
  146. }else{
  147. $this->c = 'Index';
  148. }
  149. if(isset($pathInfoArr[1])){
  150. $this->a = $pathInfoArr[1];
  151. }else{
  152. $this->a = 'Index';
  153. }
  154. }
  155. if(!class_exists($this->c.'Controller')){
  156. halt('控制器'.$this->c.'不存在');
  157. }
  158. $controllerClass = $this->c.'Controller';
  159. $controller = new $controllerClass();
  160. if(!method_exists($controller, $this->a.'Action')){
  161. halt('方法'.$this->a.'不存在');
  162. }
  163. call_user_func(array($controller,$this->a.'Action'));
  164. }
  165. /**
  166. * 自动加载函数
  167. * @param string $class 类名
  168. */
  169. public static function autoload($class){
  170. if(substr($class,-10)=='Controller'){
  171. includeIfExist(C('APP_FULL_PATH').'/Controller/'.$class.'.class.php');
  172. }elseif(substr($class,-6)=='Widget'){
  173. includeIfExist(C('APP_FULL_PATH').'/Widget/'.$class.'.class.php');
  174. }else{
  175. includeIfExist(C('APP_FULL_PATH').'/Lib/'.$class.'.class.php');
  176. }
  177. }
  178. }
  179. /**
  180. * 控制器类
  181. */
  182. class Controller {
  183. /**
  184. * 视图实例
  185. * @var View
  186. */
  187. private $_view;
  188. /**
  189. * 构造函数,初始化视图实例,调用hook
  190. */
  191. public function __construct(){
  192. $this->_view = new View();
  193. $this->_init();
  194. }
  195. /**
  196. * 前置hook
  197. */
  198. protected function _init(){}
  199. /**
  200. * 渲染模板并输出
  201. * @param null|string $tpl 模板文件路径
  202. * 参数为相对于App/View/文件的相对路径,不包含后缀名,例如index/index
  203. * 如果参数为空,则默认使用$controller/$action.php
  204. * 如果参数不包含"/",则默认使用$controller/$tpl
  205. * @return void
  206. */
  207. protected function display($tpl=''){
  208. if($tpl === ''){
  209. $trace = debug_backtrace();
  210. $controller = substr($trace[1]['class'], 0, -10);
  211. $action = substr($trace[1]['function'], 0 , -6);
  212. $tpl = $controller . '/' . $action;
  213. }elseif(strpos($tpl, '/') === false){
  214. $trace = debug_backtrace();
  215. $controller = substr($trace[1]['class'], 0, -10);
  216. $tpl = $controller . '/' . $tpl;
  217. }
  218. $this->_view->display($tpl);
  219. }
  220. /**
  221. * 为视图引擎设置一个模板变量
  222. * @param string $name 要在模板中使用的变量名
  223. * @param mixed $value 模板中该变量名对应的值
  224. * @return void
  225. */
  226. protected function assign($name,$value){
  227. $this->_view->assign($name,$value);
  228. }
  229. /**
  230. * 将数据用json格式输出至浏览器,并停止执行代码
  231. * @param array $data 要输出的数据
  232. */
  233. protected function ajaxReturn($data){
  234. echo json_encode($data);
  235. exit;
  236. }
  237. /**
  238. * 重定向至指定url
  239. * @param string $url 要跳转的url
  240. * @param void
  241. */
  242. protected function redirect($url){
  243. header("Location: $url");
  244. exit;
  245. }
  246. }
  247. /**
  248. * 视图类
  249. */
  250. class View {
  251. /**
  252. * 视图文件目录
  253. * @var string
  254. */
  255. private $_tplDir;
  256. /**
  257. * 视图文件路径
  258. * @var string
  259. */
  260. private $_viewPath;
  261. /**
  262. * 视图变量列表
  263. * @var array
  264. */
  265. private $_data = array();
  266. /**
  267. * 给tplInclude用的变量列表
  268. * @var array
  269. */
  270. private static $tmpData;
  271. /**
  272. * @param string $tplDir
  273. */
  274. public function __construct($tplDir=''){
  275. if($tplDir == ''){
  276. $this->_tplDir = './'.C('APP_PATH').'/View/';
  277. }else{
  278. $this->_tplDir = $tplDir;
  279. }
  280. }
  281. /**
  282. * 为视图引擎设置一个模板变量
  283. * @param string $key 要在模板中使用的变量名
  284. * @param mixed $value 模板中该变量名对应的值
  285. * @return void
  286. */
  287. public function assign($key, $value) {
  288. $this->_data[$key] = $value;
  289. }
  290. /**
  291. * 渲染模板并输出
  292. * @param null|string $tplFile 模板文件路径,相对于App/View/文件的相对路径,不包含后缀名,例如index/index
  293. * @return void
  294. */
  295. public function display($tplFile) {
  296. $this->_viewPath = $this->_tplDir . $tplFile . '.php';
  297. unset($tplFile);
  298. extract($this->_data);
  299. include $this->_viewPath;
  300. }
  301. /**
  302. * 用于在模板文件中包含其他模板
  303. * @param string $path 相对于View目录的路径
  304. * @param array $data 传递给子模板的变量列表,key为变量名,value为变量值
  305. * @return void
  306. */
  307. public static function tplInclude($path, $data=array()){
  308. self::$tmpData = array(
  309. 'path' => C('APP_FULL_PATH') . '/View/' . $path . '.php',
  310. 'data' => $data,
  311. );
  312. unset($path);
  313. unset($data);
  314. extract(self::$tmpData['data']);
  315. include self::$tmpData['path'];
  316. }
  317. }
  318. /**
  319. * Widget类
  320. * 使用时需继承此类,重写invoke方法,并在invoke方法中调用display
  321. */
  322. class Widget {
  323. /**
  324. * 视图实例
  325. * @var View
  326. */
  327. protected $_view;
  328. /**
  329. * Widget名
  330. * @var string
  331. */
  332. protected $_widgetName;
  333. /**
  334. * 构造函数,初始化视图实例
  335. */
  336. public function __construct(){
  337. $this->_widgetName = get_class($this);
  338. $dir = C('APP_FULL_PATH') . '/Widget/Tpl/';
  339. $this->_view = new View($dir);
  340. }
  341. /**
  342. * 处理逻辑
  343. * @param mixed $data 参数
  344. */
  345. public function invoke($data){}
  346. /**
  347. * 渲染模板
  348. * @param string $tpl 模板路径,如果为空则用类名作为模板名
  349. */
  350. protected function display($tpl=''){
  351. if($tpl == ''){
  352. $tpl = $this->_widgetName;
  353. }
  354. $this->_view->display($tpl);
  355. }
  356. /**
  357. * 为视图引擎设置一个模板变量
  358. * @param string $name 要在模板中使用的变量名
  359. * @param mixed $value 模板中该变量名对应的值
  360. * @return void
  361. */
  362. protected function assign($name,$value){
  363. $this->_view->assign($name,$value);
  364. }
  365. }
  366. /**
  367. * 数据库操作类
  368. * 使用方法:
  369. * DB::getInstance($conf)->query('select * from table');
  370. * 其中$conf是一个关联数组,需要包含以下key:
  371. * DB_HOST DB_USER DB_PWD DB_NAME
  372. * 可以用DB_PORT和DB_CHARSET来指定端口和编码,默认3306和utf8
  373. */
  374. class DB {
  375. /**
  376. * 数据库链接
  377. * @var resource
  378. */
  379. private $_db;
  380. /**
  381. * 保存最后一条sql
  382. * @var string
  383. */
  384. private $_lastSql;
  385. /**
  386. * 上次sql语句影响的行数
  387. * @var int
  388. */
  389. private $_rows;
  390. /**
  391. * 上次sql执行的错误
  392. * @var string
  393. */
  394. private $_error;
  395. /**
  396. * 实例数组
  397. * @var array
  398. */
  399. private static $_instance = array();
  400. /**
  401. * 构造函数
  402. * @param array $dbConf 配置数组
  403. */
  404. private function __construct($dbConf){
  405. if(!isset($dbConf['DB_CHARSET'])){
  406. $dbConf['DB_CHARSET'] = 'utf8';
  407. }
  408. $this->_db = mysql_connect($dbConf['DB_HOST'].':'.$dbConf['DB_PORT'],$dbConf['DB_USER'],$dbConf['DB_PWD']);
  409. if($this->_db === false){
  410. halt(mysql_error());
  411. }
  412. $selectDb = mysql_select_db($dbConf['DB_NAME'],$this->_db);
  413. if($selectDb === false){
  414. halt(mysql_error());
  415. }
  416. mysql_set_charset($dbConf['DB_CHARSET']);
  417. }
  418. private function __clone(){}
  419. /**
  420. * 获取DB类
  421. * @param array $dbConf 配置数组
  422. * @return DB
  423. */
  424. static public function getInstance($dbConf){
  425. if(!isset($dbConf['DB_PORT'])){
  426. $dbConf['DB_PORT'] = '3306';
  427. }
  428. $key = $dbConf['DB_HOST'].':'.$dbConf['DB_PORT'];
  429. if(!isset(self::$_instance[$key]) || !(self::$_instance[$key] instanceof self)){
  430. self::$_instance[$key] = new self($dbConf);
  431. }
  432. return self::$_instance[$key];
  433. }
  434. /**
  435. * 转义字符串
  436. * @param string $str 要转义的字符串
  437. * @return string 转义后的字符串
  438. */
  439. public function escape($str){
  440. return mysql_real_escape_string($str, $this->_db);
  441. }
  442. /**
  443. * 查询,用于select语句
  444. * @param string $sql 要查询的sql
  445. * @return bool|array 查询成功返回对应数组,失败返回false
  446. */
  447. public function query($sql){
  448. $this->_rows = 0;
  449. $this->_error = '';
  450. $this->_lastSql = $sql;
  451. $this->logSql();
  452. $res = mysql_query($sql,$this->_db);
  453. if($res === false){
  454. $this->_error = mysql_error($this->_db);
  455. $this->logError();
  456. return false;
  457. }else{
  458. $this->_rows = mysql_num_rows($res);
  459. $result = array();
  460. if($this->_rows >0) {
  461. while($row = mysql_fetch_array($res, MYSQL_ASSOC)){
  462. $result[] = $row;
  463. }
  464. mysql_data_seek($res,0);
  465. }
  466. return $result;
  467. }
  468. }
  469. /**
  470. * 查询,用于insert/update/delete语句
  471. * @param string $sql 要查询的sql
  472. * @return bool|int 查询成功返回影响的记录数量,失败返回false
  473. */
  474. public function execute($sql) {
  475. $this->_rows = 0;
  476. $this->_error = '';
  477. $this->_lastSql = $sql;
  478. $this->logSql();
  479. $result = mysql_query($sql, $this->_db) ;
  480. if ( false === $result) {
  481. $this->_error = mysql_error($this->_db);
  482. $this->logError();
  483. return false;
  484. } else {
  485. $this->_rows = mysql_affected_rows($this->_db);
  486. return $this->_rows;
  487. }
  488. }
  489. /**
  490. * 获取上一次查询影响的记录数量
  491. * @return int 影响的记录数量
  492. */
  493. public function getRows(){
  494. return $this->_rows;
  495. }
  496. /**
  497. * 获取上一次insert后生成的自增id
  498. * @return int 自增ID
  499. */
  500. public function getInsertId() {
  501. return mysql_insert_id($this->_db);
  502. }
  503. /**
  504. * 获取上一次查询的sql
  505. * @return string sql
  506. */
  507. public function getLastSql(){
  508. return $this->_lastSql;
  509. }
  510. /**
  511. * 获取上一次查询的错误信息
  512. * @return string 错误信息
  513. */
  514. public function getError(){
  515. return $this->_error;
  516. }
  517. /**
  518. * 记录sql到文件
  519. */
  520. private function logSql(){
  521. Log::sql($this->_lastSql);
  522. }
  523. /**
  524. * 记录错误日志到文件
  525. */
  526. private function logError(){
  527. $str = '[SQL ERR]'.$this->_error.' SQL:'.$this->_lastSql;
  528. Log::warn($str);
  529. }
  530. }
  531. /**
  532. * 日志类
  533. * 使用方法:Log::fatal('error msg');
  534. * 保存路径为 App/Log,按天存放
  535. * fatal和warning会记录在.log.wf文件中
  536. */
  537. class Log{
  538. /**
  539. * 打日志,支持SAE环境
  540. * @param string $msg 日志内容
  541. * @param string $level 日志等级
  542. * @param bool $wf 是否为错误日志
  543. */
  544. public static function write($msg, $level='DEBUG', $wf=false){
  545. if(function_exists('sae_debug')){ //如果是SAE,则使用sae_debug函数打日志
  546. $msg = "[{$level}]".$msg;
  547. sae_set_display_errors(false);
  548. sae_debug(trim($msg));
  549. sae_set_display_errors(true);
  550. }else{
  551. $msg = date('[ Y-m-d H:i:s ]')."[{$level}]".$msg."\r\n";
  552. $logPath = C('APP_FULL_PATH').'/Log/'.date('Ymd').'.log';
  553. if($wf){
  554. $logPath .= '.wf';
  555. }
  556. file_put_contents($logPath, $msg, FILE_APPEND);
  557. }
  558. }
  559. /**
  560. * 打印fatal日志
  561. * @param string $msg 日志信息
  562. */
  563. public static function fatal($msg){
  564. self::write($msg, 'FATAL', true);
  565. }
  566. /**
  567. * 打印warning日志
  568. * @param string $msg 日志信息
  569. */
  570. public static function warn($msg){
  571. self::write($msg, 'WARN', true);
  572. }
  573. /**
  574. * 打印notice日志
  575. * @param string $msg 日志信息
  576. */
  577. public static function notice($msg){
  578. self::write($msg, 'NOTICE');
  579. }
  580. /**
  581. * 打印debug日志
  582. * @param string $msg 日志信息
  583. */
  584. public static function debug($msg){
  585. self::write($msg, 'DEBUG');
  586. }
  587. /**
  588. * 打印sql日志
  589. * @param string $msg 日志信息
  590. */
  591. public static function sql($msg){
  592. self::write($msg, 'SQL');
  593. }
  594. }
  595. /**
  596. * ExtException类,记录额外的异常信息
  597. */
  598. class ExtException extends Exception{
  599. /**
  600. * @var array
  601. */
  602. protected $extra;
  603. /**
  604. * @param string $message
  605. * @param array $extra
  606. * @param int $code
  607. * @param null $previous
  608. */
  609. public function __construct($message = "", $extra = array(), $code = 0, $previous = null){
  610. $this->extra = $extra;
  611. parent::__construct($message, $code, $previous);
  612. }
  613. /**
  614. * 获取额外的异常信息
  615. * @return array
  616. */
  617. public function getExtra(){
  618. return $this->extra;
  619. }
  620. }

人气教程排行