首页 后端开发 php教程 超简洁PHPMVC

超简洁PHPMVC

Jul 25, 2016 am 08:47 AM

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


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

会话如何劫持工作,如何在PHP中减轻它? 会话如何劫持工作,如何在PHP中减轻它? Apr 06, 2025 am 12:02 AM

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

描述扎实的原则及其如何应用于PHP的开发。 描述扎实的原则及其如何应用于PHP的开发。 Apr 03, 2025 am 12:04 AM

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

在PHPStorm中如何进行CLI模式的调试? 在PHPStorm中如何进行CLI模式的调试? Apr 01, 2025 pm 02:57 PM

在PHPStorm中如何进行CLI模式的调试?在使用PHPStorm进行开发时,有时我们需要在命令行界面(CLI)模式下调试PHP�...

如何在系统重启后自动设置unixsocket的权限? 如何在系统重启后自动设置unixsocket的权限? Mar 31, 2025 pm 11:54 PM

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

解释PHP中的晚期静态绑定(静态::)。 解释PHP中的晚期静态绑定(静态::)。 Apr 03, 2025 am 12:04 AM

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。

如何用PHP的cURL库发送包含JSON数据的POST请求? 如何用PHP的cURL库发送包含JSON数据的POST请求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL库发送JSON数据在PHP开发中,经常需要与外部API进行交互,其中一种常见的方式是使用cURL库发送POST�...

See all articles