DebugHelper.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. namespace loyalsoft;
  3. /**
  4. * 调试辅助脚本,目前主要集中在输出功能.
  5. * @version
  6. * 2.0.1 添加检查PHP version和extensions的方法. --gwang 2019年8月16日 15:15:48
  7. * 1.0.0 Created at 2016-7-1. by --gwang
  8. * @author gwang (mail@wanggangzero.cn)
  9. * @copyright © 2016-7-1, SJZ LoyalSoft Corporation & gwang. All rights reserved.
  10. */
  11. class DebugHelper {
  12. /**
  13. * @return bool 调试输出是否开启
  14. */
  15. private static function isDebugging() {
  16. return defined("GAME_ONLINE") && !GAME_ONLINE; # 线上版屏蔽输出
  17. }
  18. //
  19. // <editor-fold defaultstate="collapsed" desc="assert">
  20. /**
  21. * 逻辑断言,不受系统断言状态影响,可以用于生产环境的简单判断,比如:参数非法,参数缺失等
  22. * @param type $condition
  23. * @param int/string $err 如果是int值,则当作Errcode处理,否则当作字符串处理
  24. */
  25. static function assert($condition, $err) {
  26. if (!$condition) { # 断言失败
  27. if (is_int($err)) {
  28. Err($err, "Assert faild!" . self::get_call_stack(6));
  29. } else {
  30. Err(ErrCode::err_assert, $err . self::get_call_stack(6));
  31. }
  32. // trigger_error($err, E_USER_ERROR); # 触发错误
  33. }
  34. }
  35. /**
  36. * 接管系统的断言失败处理函数(调试用,若要检查参数是否完整,请用Resp::assert())
  37. * 注意:方法内部依赖于GAME_ONLINE标志,若为内网调试则打开断言,
  38. * 若为线上环境则关闭断言(提升安全性和部分性能)
  39. */
  40. static function cover_assert_handler() {
  41. assert_options(ASSERT_ACTIVE, !GAME_ONLINE); # 设置断言标志
  42. assert_options(ASSERT_BAIL, true);
  43. assert_options(ASSERT_WARNING, false);
  44. assert_options(ASSERT_CALLBACK, array('DebugHelper', 'my_assert_handler')); # 设置回调函数
  45. }
  46. /**
  47. * 断言处理函数
  48. * @param type $file
  49. * @param type $line
  50. * @param type $code
  51. * @param type $desc
  52. */
  53. private static function my_assert_handler($file, $line, $code, $desc) {
  54. $msg = "<hr>Assertion Failed:
  55. File '$file'<br />
  56. Line '$line'<br />
  57. Code '$code'<br />
  58. Desc '{$desc}'<br />
  59. <hr />";
  60. Err(Err::err_assert, $msg); # 给客户端返回值
  61. // trigger_error($msg, E_USER_ERROR); # 抛出一个err
  62. }
  63. // </editor-fold>
  64. //
  65. /**
  66. * 浏览器打印调试信息
  67. * @param mixed $msg 对象或数组将会被序列化为json串
  68. */
  69. public static function debug($msg) {
  70. if (self::isDebugging()) {
  71. if (is_array($msg) || is_object($msg)) {
  72. $msg = json_encode($msg);
  73. }
  74. echoLine('[' . TimeUtil::dtCurrent() . ']| ' . $msg);
  75. }
  76. }
  77. /**
  78. * var_dump输出变量,统一入口的话, 上线的时候通过统一变量关闭,防止漏删除的意外输出.
  79. * @param mixed $obj
  80. */
  81. public static function var_dump($obj) {
  82. if (!self::isDebugging()) {
  83. return;
  84. }
  85. $pos = self::get_call_stack();
  86. $stack = explode('<br/>', $pos);
  87. $n = 3 > count($stack) ? count($stack) : 3;
  88. for ($i = 0; $i < $n; $i++) {
  89. echoLine($stack[$i]);
  90. }
  91. echoLine(); # 换个行
  92. var_dump($obj);
  93. }
  94. /**
  95. * 浏览器输出调用堆栈
  96. * @return void
  97. */
  98. public static function print_stack_trace() {
  99. /* * * * *
  100. * 因为debug_print_backtrace()格式不太易读,自己调整下输出样式
  101. * * * */
  102. $html = self::get_call_stack();
  103. self::debug($html);
  104. }
  105. /**
  106. * 尝试从array中取出一个命名变量, Ps.可以取消5.3中的Notice
  107. * @param arry $arr
  108. * @param string $strFieldName
  109. * @return mixed
  110. */
  111. static private function arr_get($arr, $strFieldName) {
  112. if (isset($arr[$strFieldName])) {
  113. return $arr[$strFieldName];
  114. }
  115. return null;
  116. }
  117. /**
  118. * 获得调用堆栈
  119. * @param int $levelnum 想要获得的调用层次,default is 3
  120. * @return string formated string
  121. */
  122. static public function get_call_stack($levelnum = 3) {
  123. $array = debug_backtrace();
  124. $outHtml = PHP_EOL;
  125. array_shift($array); # 移除get_call_stack函数自身
  126. $n = 1;
  127. foreach ($array as $row) {
  128. $outHtml .= "\t" . CommUtil::str2UTF8(self::arr_get($row, 'file')) # windows下路径(gb2312)转码
  129. . ', row: ' . self::arr_get($row, 'line') . ', method: ' # line
  130. . self::arr_get($row, 'function') . ";<br/>" . PHP_EOL; # func
  131. if ($levelnum <= $n++) {
  132. break;
  133. }
  134. }
  135. return $outHtml;
  136. }
  137. /**
  138. * 浏览器弹窗提示
  139. * @param string $msg
  140. */
  141. public static function alert($msg) {
  142. if (self::isDebugging()) {
  143. echo "<Script language=\"javascript\">alert(\"" . $msg . "\");</Script>";
  144. }
  145. }
  146. /**
  147. * 检查模块是否加载
  148. * @param string[] $arr 要检查的模块名称
  149. */
  150. public static function checkModules($arr = array()) {
  151. $default = array(# # 基础模块
  152. "curl",
  153. "mbstring",
  154. "openssl",
  155. "pdo_mysql",
  156. "sockets",
  157. "zlib",
  158. );
  159. $r_modules = array_merge($default, $arr); # 合并指定模块
  160. $diff = array_diff($r_modules, get_loaded_extensions()); # 判断缺失模块
  161. if (count($diff)) { # 确实缺失模块
  162. die("require modules: " . implode(' ,', $diff)); # 直接结束运行
  163. }
  164. return true; # 返回true
  165. }
  166. /**
  167. * 检查PHP版本
  168. * @param string $ver 最低版本字符串类似于7.3.5
  169. */
  170. public static function checkkPHPVersion($ver = null) {
  171. $default_ver = "5.4.16";
  172. $r_ver = isset($ver) ? $ver : $default_ver;
  173. if (version_compare(PHP_VERSION, $r_ver, '<')) {
  174. die('<font color="red">This code request at least PHP version ' . $r_ver #
  175. . ', Current version: ' . PHP_VERSION . ".</font><br/>" . PHP_EOL);
  176. }
  177. }
  178. }