DebugHelper.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. * 尝试从array中取出一个命名变量, Ps.可以取消5.3中的Notice
  20. * @param arry $arr
  21. * @param string $strFieldName
  22. * @return mixed
  23. */
  24. private static function arr_get($arr, $strFieldName) {
  25. if (isset($arr[$strFieldName])) {
  26. return $arr[$strFieldName];
  27. }
  28. return null;
  29. }
  30. //
  31. // <editor-fold defaultstate="collapsed" desc="assert">
  32. /**
  33. * 逻辑断言,不受系统断言状态影响,可以用于生产环境的简单判断,比如:参数非法,参数缺失等
  34. * @param type $condition
  35. * @param int/string $err 如果是int值,则当作Errcode处理,否则当作字符串处理
  36. */
  37. static function assert($condition, $err) {
  38. if (!$condition) { # 断言失败
  39. if (is_int($err)) {
  40. Err($err, "Assert faild!" . self::get_call_stack(6));
  41. } else {
  42. Err(ErrCode::err_assert, $err . self::get_call_stack(6));
  43. }
  44. // trigger_error($err, E_USER_ERROR); # 触发错误
  45. }
  46. }
  47. /**
  48. * 接管系统的断言失败处理函数(调试用,若要检查参数是否完整,请用Resp::assert())
  49. * 注意:方法内部依赖于GAME_ONLINE标志,若为内网调试则打开断言,
  50. * 若为线上环境则关闭断言(提升安全性和部分性能)
  51. */
  52. static function cover_assert_handler() {
  53. assert_options(ASSERT_ACTIVE, !GAME_ONLINE); # 设置断言标志
  54. assert_options(ASSERT_BAIL, true);
  55. assert_options(ASSERT_WARNING, false);
  56. assert_options(ASSERT_CALLBACK, array('DebugHelper', 'my_assert_handler')); # 设置回调函数
  57. }
  58. /**
  59. * 断言处理函数
  60. * @param type $file
  61. * @param type $line
  62. * @param type $code
  63. * @param type $desc
  64. */
  65. private static function my_assert_handler($file, $line, $code, $desc) {
  66. $msg = "<hr>Assertion Failed:
  67. File '$file'<br />
  68. Line '$line'<br />
  69. Code '$code'<br />
  70. Desc '{$desc}'<br />
  71. <hr />";
  72. Err(Err::err_assert, $msg); # 给客户端返回值
  73. // trigger_error($msg, E_USER_ERROR); # 抛出一个err
  74. }
  75. // </editor-fold>
  76. //
  77. /**
  78. * 浏览器打印调试信息
  79. * @param mixed $msg 对象或数组将会被序列化为json串
  80. */
  81. public static function debug($msg) {
  82. if (self::isDebugging()) {
  83. if (is_array($msg) || is_object($msg)) {
  84. $msg = json_encode($msg);
  85. }
  86. echoLine('[' . TimeUtil::dtCurrent() . ']| ' . $msg);
  87. }
  88. }
  89. /**
  90. * var_dump输出变量,统一入口的话, 上线的时候通过统一变量关闭,防止漏删除的意外输出.
  91. * @param mixed $obj
  92. */
  93. public static function var_dump($obj) {
  94. if (!self::isDebugging()) {
  95. return;
  96. }
  97. $pos = self::get_call_stack();
  98. $stack = explode('<br/>', $pos);
  99. $n = 3 > count($stack) ? count($stack) : 3;
  100. for ($i = 0; $i < $n; $i++) {
  101. echoLine($stack[$i]);
  102. }
  103. echoLine(); # 换个行
  104. var_dump($obj);
  105. }
  106. /**
  107. * 浏览器输出调用堆栈
  108. * @return void
  109. */
  110. public static function print_stack_trace() {
  111. /* * * * *
  112. * 因为debug_print_backtrace()格式不太易读,自己调整下输出样式
  113. * * * */
  114. $html = self::get_call_stack();
  115. self::debug($html);
  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. }
  165. /**
  166. * 检查PHP版本
  167. * @param string $ver 最低版本字符串类似于7.3.5
  168. */
  169. public static function checkkPHPVersion($ver = null) {
  170. $default_ver = "5.4.16";
  171. $r_ver = isset($ver) ? $ver : $default_ver;
  172. if (version_compare(PHP_VERSION, $r_ver, '<')) {
  173. die('<font color="red">This code request at least PHP version ' . $r_ver #
  174. . ', Current version: ' . PHP_VERSION . ".</font><br/>" . PHP_EOL);
  175. }
  176. }
  177. }